From ffe695112870787e2dbeac82aa54af2143bd648d Mon Sep 17 00:00:00 2001 From: Aracon Date: Sat, 13 Jun 2015 13:30:13 +0300 Subject: [PATCH 001/647] Added getFirstAccessToken() method Added method getFirstAccessToken() to receive access token when authorization code is known (http://dev.1c-bitrix.ru/learning/course/index.php?COURSE_ID=43&CHAPTER_ID=05379&LESSON_PATH=3913.5377.5379) --- src/bitrix24.php | 53 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/src/bitrix24.php b/src/bitrix24.php index fe56b274..3c97f4d8 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -576,7 +576,7 @@ public function getNewAccessToken() { throw new Bitrix24Exception('application id not found, you must call setRefreshToken method before'); } - elseif(is_null($applicationScope)) + elseif(empty($applicationScope)) { throw new Bitrix24Exception('application scope not found, you must call setApplicationScope method before'); } @@ -598,6 +598,55 @@ public function getNewAccessToken() return $requestResult; } + /** + * Authorize and get first access token + * @return array + * @throws Bitrix24Exception + */ + public function getFirstAccessToken($code) + { + $domain = $this->getDomain(); + $applicationId = $this->getApplicationId(); + $applicationSecret = $this->getApplicationSecret(); + //$refreshToken = $this->getRefreshToken(); + $applicationScope = $this->getApplicationScope(); + $redirectUri = $this->getRedirectUri(); + + if(is_null($domain)) + { + throw new Bitrix24Exception('domain not found, you must call setDomain method before'); + } + elseif(is_null($applicationId)) + { + throw new Bitrix24Exception('application id not found, you must call setApplicationId method before'); + } + elseif(is_null($applicationSecret)) + { + throw new Bitrix24Exception('application id not found, you must call setApplicationSecret method before'); + } + elseif(empty($applicationScope)) + { + throw new Bitrix24Exception('application scope not found, you must call setApplicationScope method before'); + } + elseif(is_null($redirectUri)) + { + throw new Bitrix24Exception('application redirect URI not found, you must call setRedirectUri method before'); + } + + $url = 'https://'.$domain."/oauth/token/". + "?client_id=".urlencode($applicationId). + "&grant_type=authorization_code". + "&client_secret=".$applicationSecret. + '&scope='.implode(',', array_map('urlencode', array_unique($applicationScope))). + '&redirect_uri='.urlencode($redirectUri). + '&code='.urlencode($_GET['code']); + + $requestResult = $this->executeRequest($url); + // handling bitrix24 api-level errors + $this->handleBitrix24APILevelErrors($requestResult, 'get first access token'); + return $requestResult; + } + /** * Сheck is access token expire, сall list of all available api-methods from B24 portal with current access token * if we have an error code expired_token then return true else return false @@ -695,4 +744,4 @@ public function getScope($isFull=false) $requestResult = $this->executeRequest($url); return $requestResult; } -} \ No newline at end of file +} From e6e2d2776ef7084fcd5d10213647341c27abb6ec Mon Sep 17 00:00:00 2001 From: mesilov Date: Tue, 23 Jun 2015 23:53:15 +0300 Subject: [PATCH 002/647] fix method isAccessTokenExpire --- src/bitrix24.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitrix24.php b/src/bitrix24.php index f131688f..fe56b274 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -618,7 +618,7 @@ public function isAccessTokenExpire() { throw new Bitrix24Exception('application id not found, you must call setAccessToken method before'); } - $url = 'https://'.$domain."/rest/methods.json?auth=".$accessToken.'&full=true'; + $url = 'https://'.$domain."/rest/app.info?auth=".$accessToken; $requestResult = $this->executeRequest($url); if('expired_token' == $requestResult['error']) { From 1c648d166ef53d918b6775c25cc7705459036f5c Mon Sep 17 00:00:00 2001 From: mesilov Date: Tue, 23 Jun 2015 23:54:52 +0300 Subject: [PATCH 003/647] fix comments in lead presets class --- src/presets/crm/lead/fields.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/presets/crm/lead/fields.php b/src/presets/crm/lead/fields.php index fc3f16ed..f25e7e14 100644 --- a/src/presets/crm/lead/fields.php +++ b/src/presets/crm/lead/fields.php @@ -5,6 +5,7 @@ * Class Fields * @link http://www.bitrixsoft.com/rest_help/crm/leads/crm_lead_fields.php * @package Bitrix24\Presets\CRM\Lead + * @todo check fields */ class Fields { @@ -49,13 +50,17 @@ class Fields */ const STATUS_DESCRIPTION = 'STATUS_DESCRIPTION'; /** - * @var string Position Can be read, can be write + * @var string Position in company structure. Can be read, can be write */ const POST = 'POST'; /** * @var string Address Can be read, can be write */ const ADDRESS = 'ADDRESS'; + /** + * @var string Address Can be read, can be write + */ + const ADDRESS_APARTMENT = 'ADDRESS_2'; /** * @var integer Currency ID Can be read, can be write */ From cf5ae150d6589f838e05e3d3b5d1a430327bafbf Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 24 Jun 2015 00:19:59 +0300 Subject: [PATCH 004/647] add changelog --- CHANGELOG.md | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..9b35647a --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,56 @@ +# bitrix24-php-sdk change log +## 0.2.0 (24.06.2015) +* add class Deal +* add class LiveFeedMessage +* add task fields presets +* add Bitrix24\CRM\Lead entity +* add some event fields in presets +* add Bitrix24\CRM\Contact entity +* changed PHP version for Composer +* fixed bug in Bitrix24\Presets\CRM\Lead +* fixed bug in class Invoice + +## 0.1.4 (18.04.2015) +* add presets for user fields data type structure +* add method Update and predefined constants in class Invoice +* add protected method handleBitrix24APILevelErrors in a base class +* add some presets for main entity +* add presets for entity Lead +* add method get in class Lead +* add class IM +* add methods get and delete for invoice entity +* add presets for class Contact +* add entity events +* add class Invoice in namespace Bitrix24\CRM +* fixed bug in Fix method isAccessTokenExpire + +## 0.1.3 (24.08.2014) +* add const TOTAL and RESULT for class \Bitrix24\Presets\Main +* add class Bitrix24\Presets\Users\Fields for Bitrix24 users fields +* add class Bitrix24\Departments\Department +* add class Bitrix24\Presets\Events for Bitrix24 event codes +* add class Bitrix24\Presets\Uri for Bitrix24 uri constants +* add class Bitrix24\Presets\Scope for Bitrix24 scope constants +* add class Bitrix24\Application +* add class Lead +* add class Events +* add class Contacts +* add a composer support +* fixed bug in main class, remove require_once instructions +* fixed bug in __construct in abstract class Bitrix24Entity + +## 0.1.2 (22.01.2014) +* add security sign support in api-call +* add class User +* add method «admin» — Check is current user admin +* add methods getRedirectUri and setRedirectUri, redirect uri arg support in method getNewAccessToken +* add a class TaskItem +* add MIT-LICENSE + +## 0.1.1 (9.10.2013) +* add namespace support +* add classes of Bitrix24 parts: tasks, sonet +* add base class Bitrix24Entity + +## 0.1.0 (26.10.2013) +* Initial release \ No newline at end of file From e6f25dda2d47e0e939b440e6f62ba73fc8e42f11 Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 24 Jun 2015 01:14:21 +0300 Subject: [PATCH 005/647] add all task items and move to namespace task --- src/classes/task.php | 31 ---- src/classes/task/checklistitem.php | 169 ++++++++++++++++++++ src/classes/task/commentitem.php | 116 ++++++++++++++ src/classes/task/elapseditem.php | 141 +++++++++++++++++ src/classes/task/item.php | 237 +++++++++++++++++++++++++++++ src/classes/task/items.php | 34 +++++ src/classes/task/planner.php | 20 +++ src/classes/tasks.php | 52 ------- 8 files changed, 717 insertions(+), 83 deletions(-) delete mode 100644 src/classes/task.php create mode 100644 src/classes/task/checklistitem.php create mode 100644 src/classes/task/commentitem.php create mode 100644 src/classes/task/elapseditem.php create mode 100644 src/classes/task/item.php create mode 100644 src/classes/task/items.php create mode 100644 src/classes/task/planner.php delete mode 100644 src/classes/tasks.php diff --git a/src/classes/task.php b/src/classes/task.php deleted file mode 100644 index c0653171..00000000 --- a/src/classes/task.php +++ /dev/null @@ -1,31 +0,0 @@ -client->call('task.item.getmanifest'); - return $result; - } - - /** - * add new task - * @link http://dev.1c-bitrix.ru/rest_help/tasks/task/item/add.php - * @link http://dev.1c-bitrix.ru/rest_help/tasks/fields.php - * @param array $taskData - * @return array new task ID - * @throws Bitrix24Exception - */ - public function add($taskData) - { - $result = $this->client->call('task.item.add', array($taskData)); - return $result; - } -} \ No newline at end of file diff --git a/src/classes/task/checklistitem.php b/src/classes/task/checklistitem.php new file mode 100644 index 00000000..34d761ea --- /dev/null +++ b/src/classes/task/checklistitem.php @@ -0,0 +1,169 @@ +client->call('task.checklistitem.getmanifest'); + return $result; + } + + /** + * Returns the list of check list elements in a task. + * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/getlist.php + * @param $taskId integer Task identifier. Required parameter. + * @param $order array Array for result sorting. The sorting field can take the following values: + * ID � check list element identifier; + * CREATED_BY � identifier of the user who has created the element; + * TOGGLED_BY � identifier of the user who has modified the check list element status; + * TOGGLED_DATE � the time when the check list element status was changed; + * TITLE � check list element header; + * SORT_INDEX � element sorting index; + * IS_COMPLETE � the element is marked as completed; + * The sorting direction can take the following values: + * asc � ascending; + * desc � descending; + * Optional. By default it is filtered by descending identifier of a check list element. + * @return array + */ + public function getList($taskId, $order) + { + $result = $this->client->call('task.checklistitem.getlist', + array( + 'TASKID' => $taskId, + 'ORDER' => $order + )); + return $result; + } + + /** + * Returns a check list element by its identifier. + * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/get.php + * @param $taskId integer Task identifier. Required parameter. + * @param $checklistItemId integer Element identifier. Required parameter. + * @return array + */ + public function get($taskId, $checklistItemId) + { + $result = $this->client->call('task.checklistitem.get', + array( + 'TASKID' => $taskId, + 'ITEMID' => $checklistItemId + )); + return $result; + } + + /** + * Adds a new check list element to a task. Returns the identifier of the added element. + * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/add.php + * @param $taskId integer Task identifier. Required parameter. + * @param $fields array Array of fields of a check list element (TITLE, SORT_INDEX, IS_COMPLETE). Required parameter. + * @return array + */ + public function add($taskId, $fields) + { + $result = $this->client->call('task.checklistitem.add', array($taskId, array($fields))); + return $result; + } + + /** + * Updates data of a check list element. + * Before updating data, it is advisable to make sure the action is permitted (task.checklistitem.isactionallowed). + * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/update.php + * @param $taskId integer Task identifier. Required parameter. + * @param $checklistItemId integer Check list element identifier. Required parameter. + * @param $fields array Array of fields of a check list elements (TITLE, SORT_INDEX, IS_COMPLETE). Required parameter. + * @return array + */ + public function update($taskId, $checklistItemId, $fields) + { + $result = $this->client->call('task.checklistitem.update', array($taskId, $checklistItemId, array($fields))); + return $result; + } + + /** + * Deletes check list element. + * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/complete.php + * @param $taskId integer Task identifier. Required parameter. + * @param $checklistItemId integer Check list element identifier. Required parameter. + * @return array + */ + public function delete($taskId, $checklistItemId) + { + $result = $this->client->call('task.checklistitem.delete', array($taskId, $checklistItemId)); + return $result; + } + + /** + * Marks a check list element as completed. + * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/complete.php + * @param $taskId integer Task identifier. Required parameter. + * @param $checklistItemId integer Check list element identifier. Required parameter. + * @return array + */ + public function complete($taskId, $checklistItemId) + { + $result = $this->client->call('task.checklistitem.complete', array($taskId, $checklistItemId)); + return $result; + } + + /** + * Marks a check list element as active again. + * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/renew.php + * @param $taskId integer Task identifier. Required parameter. + * @param $checklistItemId integer Check list element identifier. Required parameter. + * @return array + */ + public function renew($taskId, $checklistItemId) + { + $result = $this->client->call('task.checklistitem.renew', array($taskId, $checklistItemId)); + return $result; + } + + /** + * Moves a check list element and places it in the list after the indicated one. + * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/moveafteritem.php + * @param $taskId integer Task identifier. Required parameter. + * @param $checklistItemId integer Check list element identifier. Required parameter. + * @param $checklistAfterItemId integer Check list element identifier, after which the given element will be placed. Required parameter. + * @return array + */ + public function moveAfterItem($taskId, $checklistItemId, $checklistAfterItemId) + { + $result = $this->client->call('task.checklistitem.moveafteritem', array($taskId, $checklistItemId, $checklistAfterItemId)); + return $result; + } + + /** + * Checks whether the action is permitted. + * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/isactionallowed.php + * @param $taskId integer Task identifier. Required parameter. + * @param $checklistItemId integer Comment identifier. Required parameter. + * @param $actionId integer Identifier of the action to be checked: + * 1 - ACTION_ADD; + * 2 - ACTION_MODIFY; + * 3 - ACTION_REMOVE; + * 4 - ACTION_TOGGLE. + * Required parameter. + * @return array + */ + public function isActionAllowed($taskId, $checklistItemId, $actionId) + { + $result = $this->client->call('task.checklistitem.isactionallowed', array($taskId, $checklistItemId, $actionId)); + return $result; + } +} \ No newline at end of file diff --git a/src/classes/task/commentitem.php b/src/classes/task/commentitem.php new file mode 100644 index 00000000..3176bb26 --- /dev/null +++ b/src/classes/task/commentitem.php @@ -0,0 +1,116 @@ +client->call('task.commentitem.getmanifest'); + return $result; + } + + /** + * Returns the list of comments to a task. + * @see http://www.bitrixsoft.com/rest_help/tasks/task/commentitem/getlist.php + * @param $taskId integer + * @param $order array + * @param $filter array + * @return array + */ + public function getList($taskId, $order, $filter) + { + $result = $this->client->call('task.commentitem.getmanifest', + array( + 'TASKID' => $taskId, + 'ORDER' => $order, + 'FILTER'=> $filter + )); + return $result; + } + + /** + * Returns comments to a task. + * @see http://www.bitrixsoft.com/rest_help/tasks/task/commentitem/get.php + * @param $taskId integer Task identifier. Required parameter. + * @param $commentItemId integer Comment identifier. Required parameter. + * @return array + */ + public function get($taskId, $commentItemId) + { + $result = $this->client->call('task.commentitem.get', + array( + 'TASKID' => $taskId, + 'ITEMID' => $commentItemId + )); + return $result; + } + + /** + * Creates a new comment to a task. Returns the identifier to the comment added. + * @see http://www.bitrixsoft.com/rest_help/tasks/task/commentitem/add.php + * @param $taskId integer Task identifier. Required parameter. + * @param $fields array Data field array for a task (POST_MESSAGE). Required parameter. + * @return array + */ + public function add($taskId, $fields) + { + $result = $this->client->call('task.commentitem.add', array($taskId, array($fields))); + return $result; + } + + /** + * Updates the comment data. + * @see http://www.bitrixsoft.com/rest_help/tasks/task/commentitem/update.php + * @param $taskId integer Task identifier. Required parameter. + * @param $commentItemId integer Comment identifier. Required parameter. + * @param $fields array Data field array for a task (POST_MESSAGE). Required parameter. + * @return array + */ + public function update($taskId, $commentItemId, $fields) + { + $result = $this->client->call('task.commentitem.add', array($taskId, $commentItemId, array($fields))); + return $result; + } + + /** + * Delete a comment. + * @see http://www.bitrixsoft.com/rest_help/tasks/task/commentitem/delete.php + * @param $taskId integer Task identifier. Required parameter. + * @param $commentItemId integer Comment identifier. Required parameter. + * @return array + */ + public function delete($taskId, $commentItemId) + { + $result = $this->client->call('task.commentitem.add', array($taskId, $commentItemId)); + return $result; + } + + /** + * Checks if the action is permitted. + * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/isactionallowed.php + * @param $taskId integer Task identifier. Required parameter. + * @param $commentItemId integer Comment identifier. Required parameter. + * @param $actionId integer Identifier of the action to be checked: + * 1 - ACTION_COMMENT_ADD; + * 2 - ACTION_COMMENT_MODIFY; + * 3 - ACTION_COMMENT_REMOVE. + Required parameter. + * @return array + */ + public function isActionAllowed($taskId, $commentItemId, $actionId) + { + $result = $this->client->call('task.commentitem.isactionallowed', array($taskId, $commentItemId, $actionId)); + return $result; + } +} \ No newline at end of file diff --git a/src/classes/task/elapseditem.php b/src/classes/task/elapseditem.php new file mode 100644 index 00000000..76d96e0f --- /dev/null +++ b/src/classes/task/elapseditem.php @@ -0,0 +1,141 @@ +client->call('task.elapseditem.getmanifest'); + return $result; + } + + /** + * Returns a list of entries about elapsed time for a task. + * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/getlist.php + * @param $taskId integer Task identifier. Required parameter. + * @param $order array Array for result sorting. Sorting field may take the following values: + * ID � identifier of the entry about elapsed time; + * USER_ID � identifier of the user on whose behalf the entry about the elapsed time was made; + * MINUTES � elapsed time, minutes; + * SECONDS � elapsed time, seconds ; + * CREATED_DATE � entry creation date; + * DATE_START � start date; + * DATE_STOP � end date. + * Sorting direction can take the following values: + * asc � ascending; + * desc � descending; + * Optional. By default it is filtered by descending of the entry elapsed time identifier. + * @param $filter array Array of the time {"filtered_field": "filter value" [, ...]}. Filtered field can take the following values: + * ID � comment identifier; + * USER_ID � identifier of the user on whose behalf the entry about the elapsed time was made; + * CREATED_DATE � entry creation date. + * Filtration type may be indicated before the name of the field to be filtered: + * "!" � not equal; + * "<" � less; + * "<=" � less or equal; + * ">" � more; + * ">=" � more or equal. + * filter values - a single value or an array. + * Optional. By default entries are not filtered. + * @return array + */ + public function getList($taskId, $order, $filter) + { + $result = $this->client->call('task.elapseditem.getlist', + array( + 'TASKID' => $taskId, + 'ORDER' => $order, + 'FILTER' => $filter + )); + return $result; + } + + /** + * Returns an entry about elapsed time by its identifier. + * @see http://www.bitrixsoft.com/rest_help/tasks/task/elapseditem/get.php + * @param $taskId integer Task identifier. Required parameter. + * @param $elapsedItemId integer Entry identifier. Required parameter. + * @return array + */ + public function get($taskId, $elapsedItemId) + { + $result = $this->client->call('task.checklistitem.get', + array( + 'TASKID' => $taskId, + 'ITEMID' => $elapsedItemId + )); + return $result; + } + + /** + * Add time spent to the task. Return added record ID. + * @see http://www.bitrixsoft.com/rest_help/tasks/task/elapseditem/add.php + * @param $taskId integer Task identifier. Required parameter. + * @param $fields array Array of time records and comments (SECONDS and COMMENT_TEXT). MINUTES may be used instead of SECONDS, but they may not be used at the same time. + * @return array + */ + public function add($taskId, $fields) + { + $result = $this->client->call('task.elapseditem.add', array($taskId, array($fields))); + return $result; + } + + /** + * Change parameters of the specified time spent record. + * @see http://www.bitrixsoft.com/rest_help/tasks/task/elapseditem/update.php + * @param $taskId integer Task identifier. Required parameter. + * @param $elapsedItemId integer Entry identifier. Required parameter. + * @param $fields array Array of time records and comments (SECONDS and COMMENT_TEXT). MINUTES may be used instead of SECONDS, but they may not be used at the same time. + * @return array + */ + public function update($taskId, $elapsedItemId, $fields) + { + $result = $this->client->call('task.elapseditem.update', array($taskId, $elapsedItemId, array($fields))); + return $result; + } + + /** + * Delete time spent record. + * @see http://www.bitrixsoft.com/rest_help/tasks/task/elapseditem/delete.php + * @param $taskId integer Task identifier. Required parameter. + * @param $elapsedItemId integer Time spent record ID. + * @return array + */ + public function delete($taskId, $elapsedItemId) + { + $result = $this->client->call('task.elapseditem.delete', array($taskId, $elapsedItemId)); + return $result; + } + + /** + * Verify whether the action is allowed. + * @see http://www.bitrixsoft.com/rest_help/tasks/task/elapseditem/isactionallowed.php + * @param $taskId integer Task identifier. Required parameter. + * @param $elapsedItemId integer Time spent record ID. + * @param $actionId integer Identifier of the action to be checked: + * Action ID: + * 1 - ACTION_ELAPSED_TIME_ADD; + * 2 - ACTION_ELAPSED_TIME_MODIFY; + * 3 - ACTION_ELAPSED_TIME_REMOVE. + * Required parameter. + * @return array + */ + public function isActionAllowed($taskId, $elapsedItemId, $actionId) + { + $result = $this->client->call('task.elapseditem.isActionAllowed', array($taskId, $elapsedItemId, $actionId)); + return $result; + } +} \ No newline at end of file diff --git a/src/classes/task/item.php b/src/classes/task/item.php new file mode 100644 index 00000000..9691b9d6 --- /dev/null +++ b/src/classes/task/item.php @@ -0,0 +1,237 @@ +client->call('task.item.getmanifest'); + return $result; + } + + /** + * add new task + * @link http://dev.1c-bitrix.ru/rest_help/tasks/task/item/add.php + * @link http://dev.1c-bitrix.ru/rest_help/tasks/fields.php + * @param array $taskData + * @return array new task ID + * @throws Bitrix24Exception + */ + public function add($taskData) + { + $result = $this->client->call('task.item.add', array($taskData)); + return $result; + } + + /** + * Return array of task data fields (TITLE, DESCRIPTION, etc.) + * @param $taskId + * @return array + * @throws Bitrix24Exception + * @throws \Bitrix24\Bitrix24SecurityException + */ + public function getData($taskId) + { + $result = $this->client->call('task.item.getdata', array($taskId)); + return $result; + } + + /** + * Update task data. The following fields may be updated. Business logic and permissions are taken into account when updating task data. + * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/update.php + * @param $taskId integer Task ID. + * @param $taskData array List of updated fields. + * @return array + * + */ + public function update($taskId, $taskData) + { + $result = $this->client->call('task.item.update', $taskId, array($taskData)); + return $result; + } + + /** + * Delete task. + * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/delete.php + * @param $taskId integer Task ID. + * @return array + */ + public function delete($taskId) + { + $result = $this->client->call('task.item.delete', array($taskId)); + return $result; + } + + /** + * Return task description. + * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/getdescription.php + * @param $taskId integer Task ID. + * @param $format integer 1 (Corresponds to the PHP constant CTaskItem::DESCR_FORMAT_RAW) � + * description will be returned in the format it is stored in the database (HTML or BB-code), will not be sanitized; + * 2 (Corresponds to the PHP constant CTaskItem::DESCR_FORMAT_HTML) � description will be returned in HTML, will first be sanitized (if included in task module settings); + * 3 (Corresponds to the PHP constant CTaskItem::DESCR_FORMAT_PLAIN_TEXT) � description will be returned as plain text (no HTML tags). + * @return array + */ + public function getDescription($taskId, $format) + { + $result = $this->client->call('task.item.getdescription', $taskId, $format); + return $result; + } + + /** + * Return array of links to files attached to the task. + * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/getfiles.php + * @param $taskId integer Task ID. + * @return array + */ + public function getFiles($taskId) + { + $result = $this->client->call('task.item.getfiles', array($taskId)); + return $result; + } + + /** + * Return array with parent task IDs + * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/getdependson.php + * @param $taskId integer Task ID. + * @return array + */ + public function getDependSon($taskId) + { + $result = $this->client->call('task.item.getdependson', array($taskId)); + return $result; + } + + /** + * Return array of allowed task actions IDs (see PHP class constants CTaskItem). + * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/getallowedactions.php + * @param $taskId integer Task ID. + * @return array + */ + public function getAllowedActions($taskId) + { + $result = $this->client->call('task.item.getallowedactions', array($taskId)); + return $result; + } + + /** + * Return an array whose keys are acton names (the names correspond to PHP class constants CTaskItem) and values show whether the action is allowed (true) or not allowed (false). + * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/getallowedtaskactionsasstrings.php + * @param $taskId integer Task ID. + * @return array + */ + public function getAllowedTaskActionsAsStrings($taskId) + { + $result = $this->client->call('task.item.getallowedtaskactionsasstrings', array($taskId)); + return $result; + } + + /** + * Return true if action is allowed, else returns false. + * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/isactionallowed.php + * @param $taskId integer Task ID. + * @param $actionId integer Validated action ID (see CTaskItem::ACTION_* constants of PHP class CTaskItem). + * @return array + */ + public function is�ctionAllowed($taskId, $actionId) + { + $result = $this->client->call('task.item.isactionallowed', array($taskId), array($actionId)); + return $result; + } + + /** + * Delegate task to a user. + * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/delegate.php + * @param $taskId integer Task ID + * @param $userId integer New responsible person ID + * @return array + */ + public function delegate($taskId, $userId) + { + $result = $this->client->call('task.item.delegate', array($taskId), array($userId)); + return $result; + } + + /** + * Change task status to In Progress + * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/startexecution.php + * @param $taskId integer Task ID + * @return array + */ + public function startExecution($taskId) + { + $result = $this->client->call('task.item.startexecution', array($taskId)); + return $result; + } + + /** + * Change task status to Deferred + * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/defer.php + * @param $taskId integer Task ID + * @return array + */ + public function defer($taskId) + { + $result = $this->client->call('task.item.defer', array($taskId)); + return $result; + } + + /** + * Change status to Completed or Supposedly completed (requires creator's attention). + * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/complete.php + * @param $taskId integer Task ID + * @return array + */ + public function complete($taskId) + { + $result = $this->client->call('task.item.complete', array($taskId)); + return $result; + } + + /** + * Change status to Pending. + * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/renew.php + * @param $taskId integer Task ID + * @return array + */ + public function renew($taskId) + { + $result = $this->client->call('task.item.renew', array($taskId)); + return $result; + } + + /** + * Change status of task waiting for confirmation to Completed. + * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/approve.php + * @param $taskId integer Task ID + * @return array + */ + public function approve($taskId) + { + $result = $this->client->call('task.item.approve', array($taskId)); + return $result; + } + + /** + * Change status of task waiting for confirmation to Pending. + * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/disapprove.php + * @param $taskId integer Task ID + * @return array + */ + public function disapprove($taskId) + { + $result = $this->client->call('task.item.disapprove', array($taskId)); + return $result; + } +} \ No newline at end of file diff --git a/src/classes/task/items.php b/src/classes/task/items.php new file mode 100644 index 00000000..fe057ccc --- /dev/null +++ b/src/classes/task/items.php @@ -0,0 +1,34 @@ +client->call( + 'task.items.getlist', + array( + 'ORDER' => $ORDER, + 'FILTER'=> $FILTER, + 'TASKDATA'=> $TASKDATA, + array('NAV_PARAMS'=> $NAV_PARAMS) + ) + ); + return $fullResult; + } +} \ No newline at end of file diff --git a/src/classes/task/planner.php b/src/classes/task/planner.php new file mode 100644 index 00000000..0f42610a --- /dev/null +++ b/src/classes/task/planner.php @@ -0,0 +1,20 @@ +client->call('task.planner.getlist'); + return $fullResult; + } +} \ No newline at end of file diff --git a/src/classes/tasks.php b/src/classes/tasks.php deleted file mode 100644 index 2d184cf1..00000000 --- a/src/classes/tasks.php +++ /dev/null @@ -1,52 +0,0 @@ -client->call( - 'task.items.getlist', - array( - 'ORDER' => $ORDER, - 'FILTER'=> $FILTER, - 'TASKDATA'=> $TASKDATA, - array('NAV_PARAMS'=> $NAV_PARAMS) - ) - ); - - if(is_null($NAV_PARAMS)) - { - if(self::ITEMS_PER_PAGE_LIMIT <= $fullResult['total']) - { - $totalPages = intval(ceil($fullResult['total']/self::ITEMS_PER_PAGE_LIMIT)); - $fullResult["next"] = $fullResult['total']; - for($pageNumber = 2; $pageNumber <= $totalPages; $pageNumber++) - { - $nextResult = $this->client->call( - 'task.items.getlist', - array( - 'ORDER' => $ORDER, - 'FILTER'=> $FILTER, - 'TASKDATA'=> $TASKDATA, - array('NAV_PARAMS'=> array('nPageSize'=>50,'iNumPage'=>$pageNumber)) - ) - ); - $fullResult['result'] = array_merge($fullResult['result'], $nextResult['result']); - } - } - } - return $fullResult; - } -} \ No newline at end of file From f86e01939300eaeb99b58bec96fc32dfa04179d7 Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 24 Jun 2015 01:27:26 +0300 Subject: [PATCH 006/647] add all task items and move to namespace task --- CHANGELOG.md | 117 +++++++++++++++++++++++++++------------------------ 1 file changed, 62 insertions(+), 55 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b35647a..e5900baf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,56 +1,63 @@ -# bitrix24-php-sdk change log -## 0.2.0 (24.06.2015) -* add class Deal -* add class LiveFeedMessage -* add task fields presets -* add Bitrix24\CRM\Lead entity -* add some event fields in presets -* add Bitrix24\CRM\Contact entity -* changed PHP version for Composer -* fixed bug in Bitrix24\Presets\CRM\Lead -* fixed bug in class Invoice - -## 0.1.4 (18.04.2015) -* add presets for user fields data type structure -* add method Update and predefined constants in class Invoice -* add protected method handleBitrix24APILevelErrors in a base class -* add some presets for main entity -* add presets for entity Lead -* add method get in class Lead -* add class IM -* add methods get and delete for invoice entity -* add presets for class Contact -* add entity events -* add class Invoice in namespace Bitrix24\CRM -* fixed bug in Fix method isAccessTokenExpire - -## 0.1.3 (24.08.2014) -* add const TOTAL and RESULT for class \Bitrix24\Presets\Main -* add class Bitrix24\Presets\Users\Fields for Bitrix24 users fields -* add class Bitrix24\Departments\Department -* add class Bitrix24\Presets\Events for Bitrix24 event codes -* add class Bitrix24\Presets\Uri for Bitrix24 uri constants -* add class Bitrix24\Presets\Scope for Bitrix24 scope constants -* add class Bitrix24\Application -* add class Lead -* add class Events -* add class Contacts -* add a composer support -* fixed bug in main class, remove require_once instructions -* fixed bug in __construct in abstract class Bitrix24Entity - -## 0.1.2 (22.01.2014) -* add security sign support in api-call -* add class User -* add method «admin» — Check is current user admin -* add methods getRedirectUri and setRedirectUri, redirect uri arg support in method getNewAccessToken -* add a class TaskItem -* add MIT-LICENSE - -## 0.1.1 (9.10.2013) -* add namespace support -* add classes of Bitrix24 parts: tasks, sonet -* add base class Bitrix24Entity - -## 0.1.0 (26.10.2013) +# bitrix24-php-sdk change log +## 0.2.0 (24.06.2015) +* add class Deal +* add class LiveFeedMessage +* add task fields presets +* add Bitrix24\CRM\Lead entity +* add some event fields in presets +* add Bitrix24\CRM\Contact entity +* add class Bitrix24\Task\ChecklistItem +* add class Bitrix24\Task\CommentItem +* add class Bitrix24\Task\ElapsedItem +* add class Bitrix24\Task\Item +* add class Bitrix24\Task\Items +* changed PHP version for Composer +* fixed bug in Bitrix24\Presets\CRM\Lead +* fixed bug in class Invoice +* remove class Bitrix24\Task\TaskItems +* remove class Bitrix24\Task\TaskItem + +## 0.1.4 (18.04.2015) +* add presets for user fields data type structure +* add method Update and predefined constants in class Invoice +* add protected method handleBitrix24APILevelErrors in a base class +* add some presets for main entity +* add presets for entity Lead +* add method get in class Lead +* add class IM +* add methods get and delete for invoice entity +* add presets for class Contact +* add entity events +* add class Invoice in namespace Bitrix24\CRM +* fixed bug in Fix method isAccessTokenExpire + +## 0.1.3 (24.08.2014) +* add const TOTAL and RESULT for class \Bitrix24\Presets\Main +* add class Bitrix24\Presets\Users\Fields for Bitrix24 users fields +* add class Bitrix24\Departments\Department +* add class Bitrix24\Presets\Events for Bitrix24 event codes +* add class Bitrix24\Presets\Uri for Bitrix24 uri constants +* add class Bitrix24\Presets\Scope for Bitrix24 scope constants +* add class Bitrix24\Application +* add class Lead +* add class Events +* add class Contacts +* add a composer support +* fixed bug in main class, remove require_once instructions +* fixed bug in __construct in abstract class Bitrix24Entity + +## 0.1.2 (22.01.2014) +* add security sign support in api-call +* add class User +* add method «admin» — Check is current user admin +* add methods getRedirectUri and setRedirectUri, redirect uri arg support in method getNewAccessToken +* add a class TaskItem +* add MIT-LICENSE + +## 0.1.1 (9.10.2013) +* add namespace support +* add classes of Bitrix24 parts: tasks, sonet +* add base class Bitrix24Entity + +## 0.1.0 (26.10.2013) * Initial release \ No newline at end of file From c97a000f99def5f93d9617941aa66f3441f79ee9 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 16 Jul 2015 04:02:55 +0300 Subject: [PATCH 007/647] Add a Company class and Company presets --- src/classes/crm/company/company.php | 115 ++++++++++++++++++++++++++++ src/presets/crm/company/fields.php | 110 ++++++++++++++++++++++++++ 2 files changed, 225 insertions(+) create mode 100644 src/classes/crm/company/company.php create mode 100644 src/presets/crm/company/fields.php diff --git a/src/classes/crm/company/company.php b/src/classes/crm/company/company.php new file mode 100644 index 00000000..ef1d758e --- /dev/null +++ b/src/classes/crm/company/company.php @@ -0,0 +1,115 @@ +client->call( + 'crm.company.list', + array( + 'order' => $order, + 'filter'=> $filter, + 'select'=> $select, + ) + ); + return $fullResult; + } + + /** + * Add a new company to CRM + * @param array $fields array of fields + * @link http://www.bitrixsoft.com/rest_help/crm/company/crm_company_add.php + * @return array + * @throws Bitrix24Exception + * + */ + public function add($fields = array()) + { + $fullResult = $this->client->call( + 'crm.company.add', + array('fields' => $fields) + ); + return $fullResult; + } + + /** + * Updates the specified (existing) company. + * @param array $bitrix24CompanyId integer + * @param array $fields array of fields + * @link http://www.bitrixsoft.com/rest_help/crm/company/crm_company_add.php + * @return array + * @throws Bitrix24Exception + * + */ + public function update($bitrix24CompanyId, $fields = array()) + { + $fullResult = $this->client->call( + 'crm.company.update', + array('id' => $bitrix24CompanyId), + array('fields' => $fields) + ); + return $fullResult; + } + + /** + * Returns a company associated with the specified company ID. + * @link http://www.bitrixsoft.com/rest_help/crm/company/crm_company_get.php + * @param integer $bitrix24CompanyId company identifier + * @return array + * @throws Bitrix24Exception + */ + public function get($bitrix24CompanyId) + { + $fullResult = $this->client->call( + 'crm.company.get', + array('id' => $bitrix24CompanyId) + ); + return $fullResult; + } + + /** + * Deletes the specified company and all the associated objects. + * @link http://www.bitrixsoft.com/rest_help/crm/company/crm_company_delete.php + * @param integer $bitrix24CompanyId company identifier + * @return array + * @throws Bitrix24Exception + */ + public function delete($bitrix24CompanyId) + { + $fullResult = $this->client->call( + 'crm.company.delete', + array('id' => $bitrix24CompanyId) + ); + return $fullResult; + } + + /** + * Returns the description of the fields available to company. + * @link http://www.bitrixsoft.com/rest_help/crm/company/crm_company_fields.php + * @return array + * @throws Bitrix24Exception + */ + public function fields() + { + $fullResult = $this->client->call( + 'crm.company.fields' + ); + return $fullResult; + } +} \ No newline at end of file diff --git a/src/presets/crm/company/fields.php b/src/presets/crm/company/fields.php new file mode 100644 index 00000000..e213526b --- /dev/null +++ b/src/presets/crm/company/fields.php @@ -0,0 +1,110 @@ + Date: Tue, 8 Sep 2015 00:03:56 +0300 Subject: [PATCH 008/647] some fix in task entity --- src/classes/task/item.php | 8 ++++---- src/presets/task/item/fields.php | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/classes/task/item.php b/src/classes/task/item.php index 9691b9d6..c736af5b 100644 --- a/src/classes/task/item.php +++ b/src/classes/task/item.php @@ -77,10 +77,10 @@ public function delete($taskId) * Return task description. * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/getdescription.php * @param $taskId integer Task ID. - * @param $format integer 1 (Corresponds to the PHP constant CTaskItem::DESCR_FORMAT_RAW) � + * @param $format integer 1 (Corresponds to the PHP constant CTaskItem::DESCR_FORMAT_RAW) � * description will be returned in the format it is stored in the database (HTML or BB-code), will not be sanitized; - * 2 (Corresponds to the PHP constant CTaskItem::DESCR_FORMAT_HTML) � description will be returned in HTML, will first be sanitized (if included in task module settings); - * 3 (Corresponds to the PHP constant CTaskItem::DESCR_FORMAT_PLAIN_TEXT) � description will be returned as plain text (no HTML tags). + * 2 (Corresponds to the PHP constant CTaskItem::DESCR_FORMAT_HTML) � description will be returned in HTML, will first be sanitized (if included in task module settings); + * 3 (Corresponds to the PHP constant CTaskItem::DESCR_FORMAT_PLAIN_TEXT) � description will be returned as plain text (no HTML tags). * @return array */ public function getDescription($taskId, $format) @@ -144,7 +144,7 @@ public function getAllowedTaskActionsAsStrings($taskId) * @param $actionId integer Validated action ID (see CTaskItem::ACTION_* constants of PHP class CTaskItem). * @return array */ - public function is�ctionAllowed($taskId, $actionId) + public function isActionAllowed($taskId, $actionId) { $result = $this->client->call('task.item.isactionallowed', array($taskId), array($actionId)); return $result; diff --git a/src/presets/task/item/fields.php b/src/presets/task/item/fields.php index 93d5e609..a46e720d 100644 --- a/src/presets/task/item/fields.php +++ b/src/presets/task/item/fields.php @@ -16,7 +16,7 @@ class Fields */ const DESCRIPTION = 'DESCRIPTION'; /** - * @var \DateTime Specifies the task deadline date. Read, write + * @var string Specifies the task deadline date. Read, write */ const DEADLINE = 'DEADLINE'; /** From 3e9ae42588638df6ba540598124ebf0cb6b532e4 Mon Sep 17 00:00:00 2001 From: mesilov Date: Tue, 8 Sep 2015 00:05:02 +0300 Subject: [PATCH 009/647] add crm.additional entity --- src/classes/crm/additional/duplicate.php | 31 ++++++++++++++++++++++ src/presets/crm/additional/entitytypes.php | 30 +++++++++++++++++++++ src/presets/crm/additional/fields.php | 22 +++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 src/classes/crm/additional/duplicate.php create mode 100644 src/presets/crm/additional/entitytypes.php create mode 100644 src/presets/crm/additional/fields.php diff --git a/src/classes/crm/additional/duplicate.php b/src/classes/crm/additional/duplicate.php new file mode 100644 index 00000000..96f41b74 --- /dev/null +++ b/src/classes/crm/additional/duplicate.php @@ -0,0 +1,31 @@ +client->call('crm.duplicate.findbycomm', + array( + 'type' => $communicationType, + 'values'=> $arValues, + 'entity_type'=> $entityType, + ) + ); + return $result; + } +} \ No newline at end of file diff --git a/src/presets/crm/additional/entitytypes.php b/src/presets/crm/additional/entitytypes.php new file mode 100644 index 00000000..dae84893 --- /dev/null +++ b/src/presets/crm/additional/entitytypes.php @@ -0,0 +1,30 @@ + Date: Tue, 8 Sep 2015 00:05:49 +0300 Subject: [PATCH 010/647] add preset lang --- src/presets/lang.php | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/presets/lang.php diff --git a/src/presets/lang.php b/src/presets/lang.php new file mode 100644 index 00000000..991c5b0f --- /dev/null +++ b/src/presets/lang.php @@ -0,0 +1,41 @@ + Date: Wed, 23 Sep 2015 23:28:29 +0300 Subject: [PATCH 011/647] add class CRM\LEAD\UserField --- src/classes/crm/lead/userfield.php | 86 +++++++++++++++++++++++ src/presets/crm/lead/userfield/fields.php | 31 ++++++++ 2 files changed, 117 insertions(+) create mode 100644 src/classes/crm/lead/userfield.php create mode 100644 src/presets/crm/lead/userfield/fields.php diff --git a/src/classes/crm/lead/userfield.php b/src/classes/crm/lead/userfield.php new file mode 100644 index 00000000..720cfbc3 --- /dev/null +++ b/src/classes/crm/lead/userfield.php @@ -0,0 +1,86 @@ +client->call( + 'crm.lead.userfield.list', + array( + 'order' => $order, + 'filter'=> $filter + ) + ); + return $fullResult; + } + + /** + * Get item userfield + * @link http://dev.1c-bitrix.ru/rest_help/crm/leads/crm_lead_userfield_get.php + * @param integer $userfieldId - lead userfield id + * @return array + */ + public function get($userfieldId) + { + $fullResult = $this->client->call( + 'crm.lead.userfield.get', + array('id' => $userfieldId) + ); + return $fullResult; + } + + /** + * delete userfield + * @link http://dev.1c-bitrix.ru/rest_help/crm/leads/crm_lead_userfield_delete.php + * @param integer $userfieldId - lead userfield id + * @return array + */ + public function delete($userfieldId) + { + $fullResult = $this->client->call( + 'crm.lead.userfield.delete', + array('id' => $userfieldId) + ); + return $fullResult; + } + + /** + * get list of lead userfield fields with description + * @link http://dev.1c-bitrix.ru/rest_help/crm/leads/crm_lead_userfield_fields.php + * @return array + */ + public function fields() + { + $fullResult = $this->client->call( + 'crm.userfield.fields' + ); + return $fullResult; + } + + /** + * Add a new userfield to lead + * @param array $fields array of fields + * @link http://dev.1c-bitrix.ru/rest_help/crm/leads/crm_lead_userfield_add.php + * @return array + */ + public function add($fields = array()) + { + $fullResult = $this->client->call( + 'crm.lead.userfield.add', + array('fields' => $fields) + ); + return $fullResult; + } +} \ No newline at end of file diff --git a/src/presets/crm/lead/userfield/fields.php b/src/presets/crm/lead/userfield/fields.php new file mode 100644 index 00000000..93e06fd5 --- /dev/null +++ b/src/presets/crm/lead/userfield/fields.php @@ -0,0 +1,31 @@ + Date: Fri, 2 Oct 2015 20:05:24 +0300 Subject: [PATCH 012/647] add class App - information about application and portal --- src/classes/app/app.php | 22 +++++++++++ src/presets/app/app.php | 85 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 src/classes/app/app.php create mode 100644 src/presets/app/app.php diff --git a/src/classes/app/app.php b/src/classes/app/app.php new file mode 100644 index 00000000..1d6fb866 --- /dev/null +++ b/src/classes/app/app.php @@ -0,0 +1,22 @@ +client->call('app.info', array('state' => $this->client->getSecuritySignSalt())); + return $result; + } +} \ No newline at end of file diff --git a/src/presets/app/app.php b/src/presets/app/app.php new file mode 100644 index 00000000..05282d5b --- /dev/null +++ b/src/presets/app/app.php @@ -0,0 +1,85 @@ + Date: Sat, 3 Oct 2015 10:32:03 +0300 Subject: [PATCH 013/647] add Bitrix24WrongClientException --- src/bitrix24.php | 6 +++++- src/bitrix24exception.php | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/bitrix24.php b/src/bitrix24.php index 3c97f4d8..111f41e8 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -526,7 +526,11 @@ protected function handleBitrix24APILevelErrors($arRequestResult, $methodName) if (!strlen($errDescription)) { $errName = $arRequestResult['error'].PHP_EOL; } - $errorMsg = $errName.$errDescription.'in call: [ '.$methodName.' ]'; + $errorMsg = sprintf('%s %s in call [ %s ]', $errName, $errDescription, $methodName); + if('wrong_client' === strtolower(trim($errName))) + { + throw new Bitrix24WrongClientException($errorMsg); + } throw new Bitrix24ApiException($errorMsg); } return null; diff --git a/src/bitrix24exception.php b/src/bitrix24exception.php index f69b6636..0cb4fc7e 100644 --- a/src/bitrix24exception.php +++ b/src/bitrix24exception.php @@ -6,10 +6,12 @@ * \Bitrix24Exception — base class * \Bitrix24IoException — I/O network errors * \Bitrix24ApiException — API level errors + * \Bitrix24WrongClientException - Wrong client or application will be deleted from portal * \Bitrix24SecurityException — Security errors for protected methods */ namespace Bitrix24; class Bitrix24Exception extends \Exception {} class Bitrix24IoException extends Bitrix24Exception {} class Bitrix24ApiException extends Bitrix24Exception {} -class Bitrix24SecurityException extends Bitrix24Exception {} \ No newline at end of file +class Bitrix24WrongClientException extends Bitrix24ApiException {} +class Bitrix24SecurityException extends Bitrix24Exception {} From 4a4110be4c1b067ce874fd5c51b208a96ae29409 Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Sun, 4 Oct 2015 11:12:37 +0300 Subject: [PATCH 014/647] Add methods Lead::Update, Lead::Delete --- src/classes/crm/lead/lead.php | 36 +++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/classes/crm/lead/lead.php b/src/classes/crm/lead/lead.php index 9d32e1c0..dd0375f3 100644 --- a/src/classes/crm/lead/lead.php +++ b/src/classes/crm/lead/lead.php @@ -67,4 +67,40 @@ public function fields() ); return $fullResult; } + + /** + * @link https://training.bitrix24.com/rest_help/crm/leads/crm_lead_update.php + * @param integer $leadId Specifies the lead ID + * @param array $fields An array in format array("field"=>"value"[, ...]) containing values for the fields that need to be updated. + * The fields can be one or more of those returned by crm.lead.fields. + * @param array $params Set of parameters. REGISTER_SONET_EVENT - performs registration of a change event in a lead in the Activity Stream. + * The lead's Responsible person will also receive notification. + * @return array + */ + public function update($leadId, $fields = array(), $params = array()) + { + $fullResult = $this->client->call( + 'crm.lead.update', + array( + 'id' => $leadId, + 'fields' => $fields, + 'params' => $params + ) + ); + return $fullResult; + } + + /** + * Deletes the specified lead and all the associated objects. + * @param integer $leadId + * @return array + */ + public function delete($leadId) + { + $fullResult = $this->client->call( + 'crm.lead.delete', + array('id' => $leadId) + ); + return $fullResult; + } } \ No newline at end of file From 48139d9774ab86851c6bff6b8f28bb0027903028 Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Sun, 11 Oct 2015 02:33:41 +0300 Subject: [PATCH 015/647] add presets to CRM\Deal entity, update Im class --- src/classes/im/im.php | 15 ++++- src/presets/crm/deal/fields.php | 102 ++++++++++++++++++++++++++++++++ src/presets/im/fields.php | 17 ++++++ 3 files changed, 131 insertions(+), 3 deletions(-) create mode 100644 src/presets/crm/deal/fields.php create mode 100644 src/presets/im/fields.php diff --git a/src/classes/im/im.php b/src/classes/im/im.php index 6d45c5d0..2a077d1e 100644 --- a/src/classes/im/im.php +++ b/src/classes/im/im.php @@ -2,6 +2,7 @@ namespace Bitrix24\Im; use Bitrix24\Bitrix24Entity; use Bitrix24\Bitrix24Exception; +use Bitrix24\Presets\Im\Fields as B24ImFields; /** * Class Im @@ -11,12 +12,16 @@ class Im extends Bitrix24Entity { /** * send notification to user + * @link https://training.bitrix24.com/rest_help/im/im_notify.php * @param $userId integer bitrix24 user identifier * @param $message string message to user, support some html tags + * @param $notifyType string + * - SYSTEM send message from current application + * - USER send message from current user, default value * @return array * @throws Bitrix24Exception */ - public function notify($userId, $message) + public function notify($userId, $message, $notifyType = B24ImFields::NOTIFY_TYPE_USER) { if(is_null($userId)) { @@ -26,12 +31,16 @@ public function notify($userId, $message) { throw new Bitrix24Exception('message is null'); } - + elseif(!in_array(strtoupper($notifyType), array(B24ImFields::NOTIFY_TYPE_SYSTEM, B24ImFields::NOTIFY_TYPE_USER), true)) + { + throw new Bitrix24Exception('unknown notifyType'); + } $fullResult = $this->client->call( 'im.notify', array( 'to' => $userId, - 'message' => $message + 'message' => $message, + 'type' => strtoupper($notifyType) ) ); return $fullResult; diff --git a/src/presets/crm/deal/fields.php b/src/presets/crm/deal/fields.php new file mode 100644 index 00000000..36f7a3c8 --- /dev/null +++ b/src/presets/crm/deal/fields.php @@ -0,0 +1,102 @@ + Date: Tue, 13 Oct 2015 13:36:11 +0300 Subject: [PATCH 016/647] Added $start param to crm.company.list call --- src/classes/crm/company/company.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/classes/crm/company/company.php b/src/classes/crm/company/company.php index ef1d758e..33dda014 100644 --- a/src/classes/crm/company/company.php +++ b/src/classes/crm/company/company.php @@ -15,10 +15,11 @@ class Company extends Bitrix24Entity * @param array $order - order of task items * @param array $filter - filter array * @param array $select - array of collumns to select + * @param integer $start - entity number to start from (usually returned in 'next' field of previous 'crm.company.list' API call) * @return array * @throws Bitrix24Exception */ - public function getList($order = array(), $filter = array(), $select = array()) + public function getList($order = array(), $filter = array(), $select = array(), $start = 0) { $fullResult = $this->client->call( 'crm.company.list', @@ -26,6 +27,7 @@ public function getList($order = array(), $filter = array(), $select = array()) 'order' => $order, 'filter'=> $filter, 'select'=> $select, + 'start' => $start ) ); return $fullResult; @@ -112,4 +114,4 @@ public function fields() ); return $fullResult; } -} \ No newline at end of file +} From a6930ae88684ecf1d52b6687a619c593cdf245dd Mon Sep 17 00:00:00 2001 From: Pavel Smirnov Date: Tue, 13 Oct 2015 13:38:17 +0300 Subject: [PATCH 017/647] Added $start param to crm.contact.list call --- src/classes/crm/contact/contact.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/classes/crm/contact/contact.php b/src/classes/crm/contact/contact.php index f981facf..657d60d3 100644 --- a/src/classes/crm/contact/contact.php +++ b/src/classes/crm/contact/contact.php @@ -11,11 +11,12 @@ class Contact extends Bitrix24Entity * @param array $order - order of task items * @param array $filter - filter array * @param array $select - array of collumns to select + * @param integer $start - entity number to start from (usually returned in 'next' field of previous 'crm.contact.list' API call) * @return array * @throws Bitrix24Exception * */ - public function getList($order = array(), $filter = array(), $select = array()) + public function getList($order = array(), $filter = array(), $select = array(), $start = 0) { $fullResult = $this->client->call( 'crm.contact.list', @@ -23,6 +24,7 @@ public function getList($order = array(), $filter = array(), $select = array()) 'order' => $order, 'filter'=> $filter, 'select'=> $select, + 'start' => $start ) ); return $fullResult; @@ -74,4 +76,4 @@ public function fields() ); return $fullResult; } -} \ No newline at end of file +} From e66f8d89cedd96434aa6a553aa2a01286a08364a Mon Sep 17 00:00:00 2001 From: Pavel Smirnov Date: Tue, 13 Oct 2015 13:40:35 +0300 Subject: [PATCH 018/647] Added $start param to crm.deal.list call --- src/classes/crm/deal/deal.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/classes/crm/deal/deal.php b/src/classes/crm/deal/deal.php index d4fa60ca..710ee160 100644 --- a/src/classes/crm/deal/deal.php +++ b/src/classes/crm/deal/deal.php @@ -69,9 +69,10 @@ public function get($dealId) * @param array $order - order of deal items * @param array $filter - filter array * @param array $select - array of collumns to select + * @param integer $start - entity number to start from (usually returned in 'next' field of previous 'crm.deal.list' API call) * @return array */ - public function getList($order = array(), $filter = array(), $select = array()) + public function getList($order = array(), $filter = array(), $select = array(), $start = 0) { $fullResult = $this->client->call( 'crm.deal.list', @@ -79,6 +80,7 @@ public function getList($order = array(), $filter = array(), $select = array()) 'order' => $order, 'filter'=> $filter, 'select'=> $select, + 'start' => $start ) ); return $fullResult; @@ -104,4 +106,4 @@ public function update($dealId, $dealFields) } -} \ No newline at end of file +} From 5336f21fbdf9452b7e536d15ff6edd6a99f1d097 Mon Sep 17 00:00:00 2001 From: Pavel Smirnov Date: Tue, 13 Oct 2015 13:42:21 +0300 Subject: [PATCH 019/647] Added $start param to crm.invoice.list call --- src/classes/crm/invoice/invoice.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/classes/crm/invoice/invoice.php b/src/classes/crm/invoice/invoice.php index a59a568e..8266cb7a 100644 --- a/src/classes/crm/invoice/invoice.php +++ b/src/classes/crm/invoice/invoice.php @@ -23,9 +23,10 @@ class Invoice extends Bitrix24Entity * @param array $order - order of task items * @param array $filter - filter array * @param array $select - array of collumns to select + * @param integer $start - entity number to start from (usually returned in 'next' field of previous 'crm.invoice.list' API call) * @return array */ - public function getList($order = array(), $filter = array(), $select = array()) + public function getList($order = array(), $filter = array(), $select = array(), $start = 0) { $fullResult = $this->client->call( 'crm.invoice.list', @@ -33,6 +34,7 @@ public function getList($order = array(), $filter = array(), $select = array()) 'order' => $order, 'filter'=> $filter, 'select'=> $select, + 'start' => $start ) ); return $fullResult; @@ -114,4 +116,4 @@ public function fields() ); return $fullResult; } -} \ No newline at end of file +} From 3145094c2fce6e30262b055cf32a902caa1e4cae Mon Sep 17 00:00:00 2001 From: Pavel Smirnov Date: Tue, 13 Oct 2015 13:51:24 +0300 Subject: [PATCH 020/647] Fixed phpdoc comment for crm.lead.get method wrapper --- src/classes/crm/lead/lead.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/classes/crm/lead/lead.php b/src/classes/crm/lead/lead.php index dd0375f3..3c0e9167 100644 --- a/src/classes/crm/lead/lead.php +++ b/src/classes/crm/lead/lead.php @@ -5,7 +5,7 @@ class Lead extends Bitrix24Entity { /** - * Get list of lead items. + * Get lead item by ID. * @link http://dev.1c-bitrix.ru/rest_help/crm/leads/crm_lead_get.php * @param integer $leadId - lead id * @return array @@ -103,4 +103,4 @@ public function delete($leadId) ); return $fullResult; } -} \ No newline at end of file +} From 39c6ea3bef16743cc9308ce4a0adfaceec7a393b Mon Sep 17 00:00:00 2001 From: Pavel Smirnov Date: Tue, 13 Oct 2015 13:52:45 +0300 Subject: [PATCH 021/647] Added $start param to crm.lead.list call --- src/classes/crm/lead/lead.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/classes/crm/lead/lead.php b/src/classes/crm/lead/lead.php index 3c0e9167..aac940a0 100644 --- a/src/classes/crm/lead/lead.php +++ b/src/classes/crm/lead/lead.php @@ -25,9 +25,10 @@ public function get($leadId) * @param array $order - order of task items * @param array $filter - filter array * @param array $select - array of collumns to select + * @param integer $start - entity number to start from (usually returned in 'next' field of previous 'crm.lead.list' API call) * @return array */ - public function getList($order = array(), $filter = array(), $select = array()) + public function getList($order = array(), $filter = array(), $select = array(), $start = 0) { $fullResult = $this->client->call( 'crm.lead.list', @@ -35,6 +36,7 @@ public function getList($order = array(), $filter = array(), $select = array()) 'order' => $order, 'filter'=> $filter, 'select'=> $select, + 'start' => $start ) ); return $fullResult; From c5ce94e3b2ef9874fc52bd75d8f17d3dfea38306 Mon Sep 17 00:00:00 2001 From: Pavel Smirnov Date: Tue, 13 Oct 2015 15:34:17 +0300 Subject: [PATCH 022/647] Added Bitrix24\Crm\Invoice\Status class --- src/classes/crm/invoice/status.php | 46 ++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/classes/crm/invoice/status.php diff --git a/src/classes/crm/invoice/status.php b/src/classes/crm/invoice/status.php new file mode 100644 index 00000000..495fc395 --- /dev/null +++ b/src/classes/crm/invoice/status.php @@ -0,0 +1,46 @@ +client->call( + 'crm.invoice.status.list', + array( + 'order' => $order, + 'filter'=> $filter, + 'select'=> $select, + 'start' => $start + ) + ); + return $fullResult; + } + + /** + * get by id + * @link http://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_invoice_status_get.php + * @param integer $invoiceStatusId - invoice status identifier + * @return array + */ + public function get($invoiceStatusId) + { + $fullResult = $this->client->call( + 'crm.invoice.status.get', + array('id' => $invoiceStatusId) + ); + return $fullResult; + } + +} + From fc4f125cb057a848d25059a4318f801d6085c777 Mon Sep 17 00:00:00 2001 From: Pavel Smirnov Date: Tue, 13 Oct 2015 15:46:13 +0300 Subject: [PATCH 023/647] Added Bitrix24\Crm\Product class --- src/classes/crm/product/product.php | 48 +++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 src/classes/crm/product/product.php diff --git a/src/classes/crm/product/product.php b/src/classes/crm/product/product.php new file mode 100644 index 00000000..db8f2dc2 --- /dev/null +++ b/src/classes/crm/product/product.php @@ -0,0 +1,48 @@ +client->call( + 'crm.product.list', + array( + 'order' => $order, + 'filter'=> $filter, + 'select'=> $select, + 'start' => $start + ) + ); + return $fullResult; + } + + /** + * get product by id + * @link http://dev.1c-bitrix.ru/rest_help/crm/products/crm_product_get.php + * @param integer $productId - product item identifier + * @return array + */ + public function get($productId) + { + $fullResult = $this->client->call( + 'crm.product.get', + array('id' => $productId) + ); + return $fullResult; + } + +} + + From 3a8322cc316888a3c1ab82a0c1ae55006f090a08 Mon Sep 17 00:00:00 2001 From: Pavel Smirnov Date: Tue, 13 Oct 2015 16:02:48 +0300 Subject: [PATCH 024/647] Added Bitrix24\Crm\ProductRow class --- src/classes/crm/invoice/status.php | 2 +- src/classes/crm/productrow/productrow.php | 49 +++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 src/classes/crm/productrow/productrow.php diff --git a/src/classes/crm/invoice/status.php b/src/classes/crm/invoice/status.php index 495fc395..7cf4db20 100644 --- a/src/classes/crm/invoice/status.php +++ b/src/classes/crm/invoice/status.php @@ -21,7 +21,7 @@ public function getList($order = array(), $filter = array(), $select = array(), 'order' => $order, 'filter'=> $filter, 'select'=> $select, - 'start' => $start + 'start' => $start ) ); return $fullResult; diff --git a/src/classes/crm/productrow/productrow.php b/src/classes/crm/productrow/productrow.php new file mode 100644 index 00000000..e22111f1 --- /dev/null +++ b/src/classes/crm/productrow/productrow.php @@ -0,0 +1,49 @@ +client->call( + 'crm.productrow.list', + array( + 'order' => array(), + 'filter'=> array( + 'OWNER_TYPE'=> $ownerType, + 'OWNER_ID'=> $ownerId, + ), + 'select'=> array(), + 'start' => $start + ) + ); + return $fullResult; + } + + + /** + * get fields descriptions + * @link http://dev.1c-bitrix.ru/rest_help/crm/productrow/crm_productrow_fields.php + * @return array + */ + public function fields() + { + $fullResult = $this->client->call( + 'crm.productrow.fields', + array() + ); + return $fullResult; + } + +} + + From 64886e322fb6cec8996f379af0337c0b0a7d273c Mon Sep 17 00:00:00 2001 From: Pavel Smirnov Date: Wed, 14 Oct 2015 13:46:00 +0300 Subject: [PATCH 025/647] Added Bitrix24\Crm\Enum class --- src/classes/crm/enum/enum.php | 109 ++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 src/classes/crm/enum/enum.php diff --git a/src/classes/crm/enum/enum.php b/src/classes/crm/enum/enum.php new file mode 100644 index 00000000..40638697 --- /dev/null +++ b/src/classes/crm/enum/enum.php @@ -0,0 +1,109 @@ +client->call( + 'crm.enum.fields' + ); + return $fullResult; + } + + + + /** + * get list of enum owner types + * @link http://dev.1c-bitrix.ru/rest_help/crm/auxiliary/enum/crm_enum_ownertype.php + * @return array + */ + public function ownerType() + { + $fullResult = $this->client->call( + 'crm.enum.ownertype' + ); + return $fullResult; + } + + /** + * get list of enum activity types + * @link http://dev.1c-bitrix.ru/rest_help/crm/auxiliary/enum/crm_enum_activitytype.php + * @return array + */ + public function activityType() + { + $fullResult = $this->client->call( + 'crm.enum.activitytype' + ); + return $fullResult; + } + + + /** + * get list of enum activity priorities + * @link http://dev.1c-bitrix.ru/rest_help/crm/auxiliary/enum/crm_enum_activitypriority.php + * @return array + */ + public function activityPriority() + { + $fullResult = $this->client->call( + 'crm.enum.activitypriority' + ); + return $fullResult; + } + + + /** + * get list of enum content types + * @link http://dev.1c-bitrix.ru/rest_help/crm/auxiliary/enum/crm_enum_contenttype.php + * @return array + */ + public function contentType() + { + $fullResult = $this->client->call( + 'crm.enum.contenttype' + ); + return $fullResult; + } + + + /** + * get list of enum activity directions + * @link http://dev.1c-bitrix.ru/rest_help/crm/auxiliary/enum/crm_enum-activitydirection.php + * @return array + */ + public function activityDirection() + { + $fullResult = $this->client->call( + 'crm.enum.activitydirection' + ); + return $fullResult; + } + + + /** + * get list of enum activity notify types + * @link http://dev.1c-bitrix.ru/rest_help/crm/auxiliary/enum/crm_enumactivitynotifytype.php + * @return array + */ + public function activityNotifyType() + { + $fullResult = $this->client->call( + 'crm.enum.activitynotifytype' + ); + return $fullResult; + } + + +} + + From db79412c1f4d54de5bc618c636e0eed40df74427 Mon Sep 17 00:00:00 2001 From: Pavel Smirnov Date: Wed, 14 Oct 2015 14:47:18 +0300 Subject: [PATCH 026/647] Added Bitrix24\Crm\Activity and Bitrix24\Crm\Activity\Communication classes --- src/classes/crm/activity/activity.php | 111 +++++++++++++++++++++ src/classes/crm/activity/communication.php | 23 +++++ 2 files changed, 134 insertions(+) create mode 100644 src/classes/crm/activity/activity.php create mode 100644 src/classes/crm/activity/communication.php diff --git a/src/classes/crm/activity/activity.php b/src/classes/crm/activity/activity.php new file mode 100644 index 00000000..f672a601 --- /dev/null +++ b/src/classes/crm/activity/activity.php @@ -0,0 +1,111 @@ +client->call( + 'crm.activity.add', + array('fields' => $fields) + ); + return $fullResult; + } + + /** + * delete activity by id + * @param integer $entityId - activity identifier + * @link http://dev.1c-bitrix.ru/rest_help/crm/rest_activity/crm_activity_delete.php + * @return array + */ + public function delete($entityId) + { + $fullResult = $this->client->call( + 'crm.activity.delete', + array('id' => $entityId) + ); + return $fullResult; + } + + /** + * get list of activity fields with description + * @link http://dev.1c-bitrix.ru/rest_help/crm/rest_activity/crm_activity_fields.php + * @return array + */ + public function fields() + { + $fullResult = $this->client->call( + 'crm.activity.fields' + ); + return $fullResult; + } + + /** + * get activity by id + * @param integer $entityId - activity identifier + * @link http://dev.1c-bitrix.ru/rest_help/crm/rest_activity/crm_activity_get.php + * @return array + */ + public function get($entityId) + { + $fullResult = $this->client->call( + 'crm.activity.get', + array('id' => $entityId) + ); + return $fullResult; + } + + /** + * Get list of activity items. + * @link http://dev.1c-bitrix.ru/rest_help/crm/rest_activity/crm_activity_list.php + * @param array $order - sort order of items + * @param array $filter - filter array + * @param array $select - array of columns to select + * @param integer $start - entity number to start from (usually returned in 'next' field of previous 'crm.activity.list' API call) + * @return array + */ + public function getList($order = array(), $filter = array(), $select = array(), $start = 0) + { + $fullResult = $this->client->call( + 'crm.activity.list', + array( + 'order' => $order, + 'filter'=> $filter, + 'select'=> $select, + 'start' => $start + ) + ); + return $fullResult; + } + + /** + * update activity by id + * @param $entityId integer - activity identifier + * @param $fields array - activity fields to update + * @link http://dev.1c-bitrix.ru/rest_help/crm/rest_activity/crm_activity_update.php + * @return array + */ + public function update($entityId, $fields) + { + $fullResult = $this->client->call( + 'crm.activity.update', + array( + 'id' => $entityId, + 'fields' => $fields + ) + ); + return $fullResult; + } + + +} + diff --git a/src/classes/crm/activity/communication.php b/src/classes/crm/activity/communication.php new file mode 100644 index 00000000..4b2f0430 --- /dev/null +++ b/src/classes/crm/activity/communication.php @@ -0,0 +1,23 @@ +client->call( + 'crm.activity.communication.fields' + ); + return $fullResult; + } + +} + From c206a3cc7658c24e38ddc9da60b571c4f64b5171 Mon Sep 17 00:00:00 2001 From: Pavel Smirnov Date: Fri, 16 Oct 2015 12:08:50 +0300 Subject: [PATCH 027/647] Added user.access method (issue #5) --- src/classes/user.php | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/classes/user.php b/src/classes/user.php index d71f2245..c9be1b37 100644 --- a/src/classes/user.php +++ b/src/classes/user.php @@ -60,4 +60,23 @@ public function get($SORT, $ORDER, $FILTER) ); return $result; } -} \ No newline at end of file + + + /** + * Check if current user has any of access rights specified by $access param + * @link http://dev.1c-bitrix.ru/rest_help/general/user_access.php + * @throws Bitrix24Exception + * @param array $access - list of access rights to check + * @return array + */ + public function access($access) + { + $result = $this->client->call('user.access', + array( + 'ACCESS' => $access + ) + ); + return $result; + } +} + From 6095e5fd263a6ad2fc898840b29a000c8760b3d9 Mon Sep 17 00:00:00 2001 From: Pavel Smirnov Date: Fri, 16 Oct 2015 12:20:04 +0300 Subject: [PATCH 028/647] Added \Bitrix24\Access class and access.name method (issue #6) --- src/classes/access.php | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/classes/access.php diff --git a/src/classes/access.php b/src/classes/access.php new file mode 100644 index 00000000..7f2676b2 --- /dev/null +++ b/src/classes/access.php @@ -0,0 +1,28 @@ +client->call( + 'access.name', + array( + 'ACCESS' => $access + ) + ); + + return $result; + } +} + From 4d04f6097a288e48601ec30b76eeb48778fbb4c9 Mon Sep 17 00:00:00 2001 From: Pavel Smirnov Date: Fri, 16 Oct 2015 14:11:44 +0300 Subject: [PATCH 029/647] Changed User class namespace from Bitrix24\User to Bitrix24 --- src/classes/user.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/classes/user.php b/src/classes/user.php index c9be1b37..c82ff2c6 100644 --- a/src/classes/user.php +++ b/src/classes/user.php @@ -1,5 +1,5 @@ Date: Sat, 17 Oct 2015 00:23:42 +0300 Subject: [PATCH 030/647] add class Bitrix24MethodNotFoundException --- src/bitrix24.php | 26 ++++++++++++++------------ src/bitrix24exception.php | 2 ++ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/bitrix24.php b/src/bitrix24.php index 111f41e8..8438c843 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -513,25 +513,27 @@ public function call($methodName, array $additionalParameters = array()) * @param $methodName * @return null * @throws Bitrix24ApiException + * @throws Bitrix24WrongClientException + * @throws Bitrix24MethodNotFoundException */ protected function handleBitrix24APILevelErrors($arRequestResult, $methodName) { if (array_key_exists('error', $arRequestResult)) { - $errName = ''; - $errDescription = ''; - if (isset($arRequestResult['error_description'])) { - $errDescription = $arRequestResult['error_description'].PHP_EOL; - } - if (!strlen($errDescription)) { - $errName = $arRequestResult['error'].PHP_EOL; - } - $errorMsg = sprintf('%s %s in call [ %s ]', $errName, $errDescription, $methodName); - if('wrong_client' === strtolower(trim($errName))) + $errorMsg = sprintf('%s - %s in call [ %s ]', $arRequestResult['error'], $arRequestResult['error_description'], $methodName); + // throw specific API-level exceptions + switch(strtoupper(trim($arRequestResult['error']))) { - throw new Bitrix24WrongClientException($errorMsg); + case 'WRONG_CLIENT': + throw new Bitrix24WrongClientException($errorMsg); + break; + case 'ERROR_METHOD_NOT_FOUND': + throw new Bitrix24MethodNotFoundException($errorMsg); + break; + default: + throw new Bitrix24ApiException($errorMsg); + break; } - throw new Bitrix24ApiException($errorMsg); } return null; } diff --git a/src/bitrix24exception.php b/src/bitrix24exception.php index 0cb4fc7e..ee1461d2 100644 --- a/src/bitrix24exception.php +++ b/src/bitrix24exception.php @@ -7,6 +7,7 @@ * \Bitrix24IoException — I/O network errors * \Bitrix24ApiException — API level errors * \Bitrix24WrongClientException - Wrong client or application will be deleted from portal + * \Bitrix24MethodNotFoundException - API-method not found * \Bitrix24SecurityException — Security errors for protected methods */ namespace Bitrix24; @@ -14,4 +15,5 @@ class Bitrix24Exception extends \Exception {} class Bitrix24IoException extends Bitrix24Exception {} class Bitrix24ApiException extends Bitrix24Exception {} class Bitrix24WrongClientException extends Bitrix24ApiException {} +class Bitrix24MethodNotFoundException extends Bitrix24ApiException {} class Bitrix24SecurityException extends Bitrix24Exception {} From 0b3b60bc10bd0660514d63e2e7dc29c69096dad7 Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Mon, 19 Oct 2015 00:05:57 +0300 Subject: [PATCH 031/647] fix constants in class CRM\LEAD\UserField --- src/presets/crm/lead/userfield/fields.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/presets/crm/lead/userfield/fields.php b/src/presets/crm/lead/userfield/fields.php index 93e06fd5..4a35e8bd 100644 --- a/src/presets/crm/lead/userfield/fields.php +++ b/src/presets/crm/lead/userfield/fields.php @@ -15,7 +15,7 @@ class Fields const LIST_COLUMN_LABEL = 'LIST_COLUMN_LABEL'; const LIST_FILTER_LABEL = 'LIST_FILTER_LABEL'; const MANDATORY = 'MANDATORY'; - const MULTIPLE = ' MULTIPLE'; + const MULTIPLE = 'MULTIPLE'; const SETTINGS = 'SETTINGS'; const SHOW_FILTER = 'SHOW_FILTER'; const SHOW_IN_LIST = 'SHOW_IN_LIST'; From 148b13415c6345c85d903e8f525e83509d8699f5 Mon Sep 17 00:00:00 2001 From: Pavel Smirnov Date: Mon, 19 Oct 2015 14:34:09 +0300 Subject: [PATCH 032/647] Moved User class to user folder. Reverted namespace to Bitrix24\User --- src/classes/{ => user}/user.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/classes/{ => user}/user.php (98%) diff --git a/src/classes/user.php b/src/classes/user/user.php similarity index 98% rename from src/classes/user.php rename to src/classes/user/user.php index c82ff2c6..c9be1b37 100644 --- a/src/classes/user.php +++ b/src/classes/user/user.php @@ -1,5 +1,5 @@ Date: Fri, 30 Oct 2015 21:52:29 +0100 Subject: [PATCH 033/647] Added Entity class --- src/classes/entity/entity.php | 310 ++++++++++++++++++++++++++++++++++ 1 file changed, 310 insertions(+) create mode 100644 src/classes/entity/entity.php diff --git a/src/classes/entity/entity.php b/src/classes/entity/entity.php new file mode 100644 index 00000000..f0be0f13 --- /dev/null +++ b/src/classes/entity/entity.php @@ -0,0 +1,310 @@ +client->call('entity.add', array( + "ENTITY" => $entity, + "NAME" => $name, + "ACCESS" => $access + )); + return $fullResult; + } + + /** + * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_update.php + * @param $entity + * @param $name + * @param $access + * @return array + * @throws Bitrix24Exception + */ + public function update($entity, $name, $access) + { + $fullResult = $this->client->call('entity.update', array( + "ENTITY" => $entity, + "NAME" => $name, + "ACCESS" => $access + )); + return $fullResult; + } + + /** + * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_rights.php + * @param $entity + * @param $access + * @return array + * @throws Bitrix24Exception + */ + public function rights($entity, $access) + { + $result = $this->client->call('entity.rights', array( + "ENTITY" => $entity, + "ACCESS" => $access + )); + return $result; + } + + /** + * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_get.php + * @param $entity + * @return array + * @throws Bitrix24Exception + */ + public function get($entity) + { + $fullResult = $this->client->call('entity.get', array( + "ENTITY" => $entity + )); + return $fullResult; + } + + /** + * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_delete.php + * @param $entity + * @return array + * @throws Bitrix24Exception + */ + public function delete($entity) + { + $fullResult = $this->client->call('entity.delete', array( + "ENTITY" => $entity + )); + return $fullResult; + } + + /** + * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_section_add.php + * @param $entity + * @param $name + * @param array $fields + * @return array + * @throws Bitrix24Exception + */ + public function sectionAdd($entity, $name, $fields = array()) + { + $arAdd = array( + "ENTITY" => $entity, + "NAME" => $name + ); + $arAdd = array_merge($arAdd, $fields); + $fullResult = $this->client->call('entity.section.add', $arAdd); + return $fullResult; + } + + /** + * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_section_get.php + * @param $entity + * @param array $sort + * @param array $filter + * @return array + * @throws Bitrix24Exception + */ + public function sectionGet($entity, $sort = array(), $filter = array()) + { + $fullResult = $this->client->call('entity.section.get', array( + "ENTITY" => $entity, + "SORT" => $sort, + "FILTER" => $filter + )); + return $fullResult; + } + + /** + * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_section_update.php + * @param $entity + * @param $id + * @param array $fields + * @return array + * @throws Bitrix24Exception + */ + public function sectionUpdate($entity, $id, $fields = array()) + { + $arUpdate = array( + "ENTITY" => $entity, + "ID" => $id + ); + $arUpdate = array_merge($arUpdate, $fields); + $fullResult = $this->client->call('entity.section.update', $arUpdate); + return $fullResult; + } + + /** + * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_section_delete.php + * @param $entity + * @param $id + * @return array + * @throws Bitrix24Exception + */ + public function sectionDelete($entity, $id) + { + $fullResult = $this->client->call('entity.section.delete', array( + "ENTITY" => $entity, + "ID" => $id + )); + return $fullResult; + } + + /** + * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_item_add.php + * @param $entity + * @param $name + * @param array $fields + * @return array + * @throws Bitrix24Exception + */ + public function itemAdd($entity, $name, $fields = array()) + { + $arAdd = array( + "ENTITY" => $entity, + "NAME" => $name + ); + $arAdd = array_merge($arAdd, $fields); + $fullResult = $this->client->call('entity.item.add', $arAdd); + return $fullResult; + } + + /** + * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_item_get.php + * @param $entity + * @param array $sort + * @param array $filter + * @return array + * @throws Bitrix24Exception + */ + public function itemGet($entity, $sort = array(), $filter = array()) + { + $fullResult = $this->client->call('entity.item.get', array( + "ENTITY" => $entity, + "SORT" => $sort, + "FILTER" => $filter + )); + return $fullResult; + } + + /** + * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_item_update.php + * @param $entity + * @param $id + * @param array $fields + * @return array + * @throws Bitrix24Exception + */ + public function itemUpdate($entity, $id, $fields = array()) + { + $arUpdate = array( + "ENTITY" => $entity, + "ID" => $id + ); + $arUpdate = array_merge($arUpdate, $fields); + $fullResult = $this->client->call('entity.item.update', $arUpdate); + return $fullResult; + } + + /** + * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_item_delete.php + * @param $entity + * @param $id + * @return array + * @throws Bitrix24Exception + */ + public function itemDelete($entity, $id) + { + $fullResult = $this->client->call('entity.item.delete', array( + "ENTITY" => $entity, + "ID" => $id + )); + return $fullResult; + } + + /** + * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_item_property_get.php + * @param $entity + * @param $property + * @return array + * @throws Bitrix24Exception + */ + public function itemPropertyGet($entity, $property) + { + $fullResult = $this->client->call('entity.item.property.get', array( + "ENTITY" => $entity, + "PROPERTY" => $property + )); + return $fullResult; + } + + /** + * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_item_property_add.php + * @param $entity + * @param $property + * @param $name + * @param $type + * @return array + * @throws Bitrix24Exception + */ + public function itemPropertyAdd($entity, $property, $name, $type) + { + $fullResult = $this->client->call('entity.item.property.add', array( + "ENTITY" => $entity, + "PROPERTY" => $property, + "NAME" => $name, + "TYPE" => $type, + + )); + return $fullResult; + } + + /** + * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_item_property_update.php + * @param $entity + * @param $property + * @param $property_new + * @param $name + * @param $type + * @return array + * @throws Bitrix24Exception + */ + public function itemPropertyUpdate($entity, $property, $property_new, $name, $type) + { + $fullResult = $this->client->call('entity.item.property.update', array( + "ENTITY" => $entity, + "PROPERTY" => $property, + "PROPERTY_NEW" => $property_new, + "NAME" => $name, + "TYPE" => $type, + )); + return $fullResult; + } + + /** + * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_item_property_delete.php + * @param $entity + * @param $property + * @return array + * @throws Bitrix24Exception + */ + public function itemPropertyDelete($entity, $property) + { + $fullResult = $this->client->call('entity.item.property.delete', array( + "ENTITY" => $entity, + "PROPERTY" => $property + )); + return $fullResult; + } +} \ No newline at end of file From 3b3db8fad34a03d6da449f1c6acd45642d13d247 Mon Sep 17 00:00:00 2001 From: yugene Date: Tue, 10 Nov 2015 00:16:31 +0300 Subject: [PATCH 034/647] - contact user fields - deal user fields --- src/classes/crm/contact/userfield.php | 74 +++++++++++++++++++++++++++ src/classes/crm/deal/userfield.php | 74 +++++++++++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 src/classes/crm/contact/userfield.php create mode 100644 src/classes/crm/deal/userfield.php diff --git a/src/classes/crm/contact/userfield.php b/src/classes/crm/contact/userfield.php new file mode 100644 index 00000000..6951d811 --- /dev/null +++ b/src/classes/crm/contact/userfield.php @@ -0,0 +1,74 @@ +client->call( + 'crm.contact.userfield.list', + array( + 'order' => $order, + 'filter'=> $filter + ) + ); + return $fullResult; + } + + /** + * Get item userfield + * @link http://dev.1c-bitrix.ru/rest_help/crm/contacts/crm_contact_userfield_get.php + * @param integer $userfieldId - contact userfield id + * @return array + */ + public function get($userfieldId) + { + $fullResult = $this->client->call( + 'crm.contact.userfield.get', + array('id' => $userfieldId) + ); + return $fullResult; + } + + /** + * Delete userfield + * @link http://dev.1c-bitrix.ru/rest_help/crm/contacts/crm_contact_userfield_delete.php + * @param integer $userfieldId - contact userfield id + * @return array + */ + public function delete($userfieldId) + { + $fullResult = $this->client->call( + 'crm.contact.userfield.delete', + array('id' => $userfieldId) + ); + return $fullResult; + } + + /** + * Add a new userfield to contact + * @param array $fields array of fields + * @link http://dev.1c-bitrix.ru/rest_help/crm/contacts/crm_contact_userfield_add.php + * @return array + */ + public function add($fields = array()) + { + $fullResult = $this->client->call( + 'crm.contact.userfield.add', + array('fields' => $fields) + ); + return $fullResult; + } +} diff --git a/src/classes/crm/deal/userfield.php b/src/classes/crm/deal/userfield.php new file mode 100644 index 00000000..66db9f55 --- /dev/null +++ b/src/classes/crm/deal/userfield.php @@ -0,0 +1,74 @@ +client->call( + 'crm.deal.userfield.list', + array( + 'order' => $order, + 'filter'=> $filter + ) + ); + return $fullResult; + } + + /** + * Get item userfield + * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_userfield_get.php + * @param integer $userfieldId - deal userfield id + * @return array + */ + public function get($userfieldId) + { + $fullResult = $this->client->call( + 'crm.deal.userfield.get', + array('id' => $userfieldId) + ); + return $fullResult; + } + + /** + * Delete userfield + * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_userfield_delete.php + * @param integer $userfieldId - deal userfield id + * @return array + */ + public function delete($userfieldId) + { + $fullResult = $this->client->call( + 'crm.deal.userfield.delete', + array('id' => $userfieldId) + ); + return $fullResult; + } + + /** + * Add a new userfield to deal + * @param array $fields array of fields + * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_userfield_add.php + * @return array + */ + public function add($fields = array()) + { + $fullResult = $this->client->call( + 'crm.deal.userfield.add', + array('fields' => $fields) + ); + return $fullResult; + } +} From 76478ead5bc1ac839c1cdd2b84d9924cf74d8848 Mon Sep 17 00:00:00 2001 From: Pavel Smirnov Date: Tue, 17 Nov 2015 13:22:42 +0300 Subject: [PATCH 035/647] Added method \Bitrix24\Bitrix24::setCustomCurlOptions() --- src/bitrix24.php | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/bitrix24.php b/src/bitrix24.php index 8438c843..10d6dbf8 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -80,6 +80,11 @@ class Bitrix24 */ protected $memberId = null; + /** + * @var array custom options for cURL + */ + protected $customCurlOptions = null; + /** * Create a object to work with Bitrix24 REST API service * @param bool $isSaveRawResponse - if true raw response from bitrix24 will be available from method getRawResponse, this is debug mode @@ -332,6 +337,18 @@ public function getApplicationSecret() return $this->applicationSecret; } + /** + * Set custom cURL options, overriding default ones + * @param array $options + * @return bool + */ + public function setCustomCurlOptions($options = array()) + { + $this->customCurlOptions = $options; + + return true; + } + /** * Return raw request, contain all cURL options array and API query. Data available after you try to call method call * numbers of array keys is const of cURL module. Example: CURLOPT_RETURNTRANSFER = 19913 @@ -369,9 +386,6 @@ public function getMethodParameters() */ protected function executeRequest($url, array $additionalParameters = array()) { - /** - * @todo add method to set custom cURL options - */ $curlOptions = array( CURLOPT_RETURNTRANSFER => true, CURLINFO_HEADER_OUT => true, @@ -383,6 +397,13 @@ protected function executeRequest($url, array $additionalParameters = array()) CURLOPT_POSTFIELDS => http_build_query($additionalParameters), CURLOPT_URL => $url ); + + if(is_array($this->customCurlOptions)) { + foreach($this->customCurlOptions as $customCurlOptionKey => $customCurlOptionValue) { + $curlOptions[$customCurlOptionKey] = $customCurlOptionValue; + } + } + $this->rawRequest = $curlOptions; $curl = curl_init(); curl_setopt_array($curl, $curlOptions); From 198439ca38e676c1417086c7f12569572f27fe30 Mon Sep 17 00:00:00 2001 From: Pavel Smirnov Date: Tue, 17 Nov 2015 13:32:36 +0300 Subject: [PATCH 036/647] Removed default value from setCustomCurlOptions() method --- src/bitrix24.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitrix24.php b/src/bitrix24.php index 10d6dbf8..255808d3 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -342,7 +342,7 @@ public function getApplicationSecret() * @param array $options * @return bool */ - public function setCustomCurlOptions($options = array()) + public function setCustomCurlOptions($options) { $this->customCurlOptions = $options; From c90ef222d0b1652e5a264e9ee6fb682e9862afba Mon Sep 17 00:00:00 2001 From: Pavel Smirnov Date: Tue, 17 Nov 2015 13:39:47 +0300 Subject: [PATCH 037/647] Added extended phpdoc comment for setCustomCurlOptions() --- src/bitrix24.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bitrix24.php b/src/bitrix24.php index 255808d3..f03eeca2 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -339,7 +339,8 @@ public function getApplicationSecret() /** * Set custom cURL options, overriding default ones - * @param array $options + * @link http://php.net/manual/en/function.curl-setopt.php + * @param array $options - array(CURLOPT_XXX => value1, CURLOPT_XXX2 => value2,...) * @return bool */ public function setCustomCurlOptions($options) From ad789dc4b124729a4270776f4f4ceead668580fc Mon Sep 17 00:00:00 2001 From: yugene Date: Mon, 23 Nov 2015 00:28:03 +0300 Subject: [PATCH 038/647] crm.contact.update --- src/classes/crm/contact/contact.php | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/classes/crm/contact/contact.php b/src/classes/crm/contact/contact.php index 657d60d3..d1c38be6 100644 --- a/src/classes/crm/contact/contact.php +++ b/src/classes/crm/contact/contact.php @@ -6,7 +6,7 @@ class Contact extends Bitrix24Entity { /** - * Get list of lead items. + * Get list of contact items. * @link http://dev.1c-bitrix.ru/rest_help/crm/contacts/crm_contact_list.php * @param array $order - order of task items * @param array $filter - filter array @@ -76,4 +76,26 @@ public function fields() ); return $fullResult; } + + /** + * @link http://dev.1c-bitrix.ru/rest_help/crm/contacts/crm_contact_update.php + * @param integer $contactId Specifies the contact ID + * @param array $fields An array in format array("field"=>"value"[, ...]) containing values for the fields that need to be updated. + * The fields can be one or more of those returned by crm.contact.fields. + * @param array $params Set of parameters. REGISTER_SONET_EVENT - performs registration of a change event in a contact in the Activity Stream. + * The contact's Responsible person will also receive notification. + * @return array + */ + public function update($contactId, $fields = array(), $params = array()) + { + $fullResult = $this->client->call( + 'crm.contact.update', + array( + 'id' => $contactId, + 'fields' => $fields, + 'params' => $params + ) + ); + return $fullResult; + } } From b994569df53966a079a6559ab1a2bc28ee6dd684 Mon Sep 17 00:00:00 2001 From: Egorov Zhenya Date: Thu, 3 Dec 2015 13:58:22 +0300 Subject: [PATCH 039/647] =?UTF-8?q?=D0=9E=D1=88=D0=B8=D0=B1=D0=BA=D0=B0,?= =?UTF-8?q?=20=D0=BA=D0=BE=D0=B3=D0=B4=D0=B0=20error=20=D0=B5=D1=81=D1=82?= =?UTF-8?q?=D1=8C,=20=D0=B0=20error=5Fdescription=20=D0=BE=D1=82=D1=81?= =?UTF-8?q?=D1=83=D1=82=D1=81=D1=82=D0=B2=D1=83=D0=B5=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/bitrix24.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitrix24.php b/src/bitrix24.php index f03eeca2..74f8ee39 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -542,7 +542,7 @@ protected function handleBitrix24APILevelErrors($arRequestResult, $methodName) { if (array_key_exists('error', $arRequestResult)) { - $errorMsg = sprintf('%s - %s in call [ %s ]', $arRequestResult['error'], $arRequestResult['error_description'], $methodName); + $errorMsg = sprintf('%s - %s in call [ %s ]', $arRequestResult['error'], (isset($arRequestResult['error_description']) ? $arRequestResult['error_description'] : ''), $methodName); // throw specific API-level exceptions switch(strtoupper(trim($arRequestResult['error']))) { From c814615879a91e6a97c1d548bd5e962eeb639989 Mon Sep 17 00:00:00 2001 From: yugene Date: Fri, 4 Dec 2015 00:15:53 +0300 Subject: [PATCH 040/647] - crm.deal.add params - crm.lead.add params --- src/classes/crm/deal/deal.php | 7 +++++-- src/classes/crm/lead/lead.php | 9 +++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/classes/crm/deal/deal.php b/src/classes/crm/deal/deal.php index 710ee160..70788073 100644 --- a/src/classes/crm/deal/deal.php +++ b/src/classes/crm/deal/deal.php @@ -7,7 +7,7 @@ class Deal extends Bitrix24Entity /** * Add a new deal to CRM * @param array $fields array of fields - * @param array $fields array of params + * @param array $params array of params * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_add.php * @return array */ @@ -15,7 +15,10 @@ public function add($fields = array(), $params = array()) { $fullResult = $this->client->call( 'crm.deal.add', - array('fields' => $fields) + array( + 'fields' => $fields, + 'params' => $params + ) ); return $fullResult; } diff --git a/src/classes/crm/lead/lead.php b/src/classes/crm/lead/lead.php index aac940a0..b2d63009 100644 --- a/src/classes/crm/lead/lead.php +++ b/src/classes/crm/lead/lead.php @@ -45,14 +45,19 @@ public function getList($order = array(), $filter = array(), $select = array(), /** * Add a new lead to CRM * @param array $fields array of fields + * @param array $params Set of parameters. REGISTER_SONET_EVENT - performs registration of a change event in a lead in the Activity Stream. + * The lead's Responsible person will also receive notification. * @link http://dev.1c-bitrix.ru/rest_help/crm/leads/crm_lead_add.php * @return array */ - public function add($fields = array()) + public function add($fields = array(), $params = array()) { $fullResult = $this->client->call( 'crm.lead.add', - array('fields' => $fields) + array( + 'fields' => $fields, + 'params' => $params + ) ); return $fullResult; } From e35931c33ebf37ed12944de5d82356a3d3958ce3 Mon Sep 17 00:00:00 2001 From: yugene Date: Fri, 4 Dec 2015 00:53:39 +0300 Subject: [PATCH 041/647] crm.contact.add params --- src/classes/crm/contact/contact.php | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/classes/crm/contact/contact.php b/src/classes/crm/contact/contact.php index d1c38be6..66ac1dff 100644 --- a/src/classes/crm/contact/contact.php +++ b/src/classes/crm/contact/contact.php @@ -30,19 +30,21 @@ public function getList($order = array(), $filter = array(), $select = array(), return $fullResult; } - /** - * Add a new contact to CRM - * @param array $fields array of fields - * @link http://dev.1c-bitrix.ru/rest_help/crm/contacts/crm_contact_add.php - * @return array - * @throws Bitrix24Exception - * - */ - public function add($fields = array()) + /** + * Add a new contact to CRM + * @param array $fields array of fields + * @param array $params array of params + * @link http://dev.1c-bitrix.ru/rest_help/crm/contacts/crm_contact_add.php + * @return array + */ + public function add($fields = array(), $params = array()) { $fullResult = $this->client->call( 'crm.contact.add', - array('fields' => $fields) + array( + 'fields' => $fields, + 'params' => $params + ) ); return $fullResult; } From 56cac0bd758a750947b60fea8ffc9f4de553d8d7 Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Tue, 5 Jan 2016 00:46:51 +0300 Subject: [PATCH 042/647] fix error in method isAccessTokenExpire, add PSR-3 compatible logger --- composer.json | 3 +- src/bitrix24.php | 192 +++++++++++++++++++++++++------------- src/bitrix24exception.php | 8 +- src/logger/stub.php | 130 ++++++++++++++++++++++++++ 4 files changed, 267 insertions(+), 66 deletions(-) create mode 100644 src/logger/stub.php diff --git a/composer.json b/composer.json index 54fba149..42913353 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,8 @@ "require": { "php": ">=5.3.2", "ext-json": "*", - "ext-curl": "*" + "ext-curl": "*", + "psr/log": "^1.0" }, "autoload": { "classmap": ["src/"] diff --git a/src/bitrix24.php b/src/bitrix24.php index 74f8ee39..c3cc4eca 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -1,5 +1,12 @@ + * @copyright 2013 - 2016 Mesilov Maxim + */ class Bitrix24 { /** @@ -11,19 +18,19 @@ class Bitrix24 * access token * @var string */ - protected $accessToken = null; + protected $accessToken; /** * refresh token * @var string */ - protected $refreshToken = null; + protected $refreshToken; /** * domain * @var string */ - protected $domain = null; + protected $domain; /** * scope @@ -35,30 +42,30 @@ class Bitrix24 * application id * @var string */ - protected $applicationId = null; + protected $applicationId; /** * application secret * @var string */ - protected $applicationSecret = null; + protected $applicationSecret; /** * raw request, contain all cURL options array and API query * @var array */ - protected $rawRequest = null; + protected $rawRequest; /** * @var array, contain all api-method parameters, vill be available after call method */ - protected $methodParameters = null; + protected $methodParameters; /** * request info data structure акщь curl_getinfo function * @var array */ - protected $requestInfo = null; + protected $requestInfo; /** * @var bool if true raw response from bitrix24 will be available from method getRawResponse, this is debug mode @@ -68,30 +75,38 @@ class Bitrix24 /** * @var array raw response from bitrix24 */ - protected $rawResponse = null; + protected $rawResponse; /** * @var string redirect URI from application settings */ - protected $redirectUri = null; + protected $redirectUri; /** * @var string portal GUID */ - protected $memberId = null; + protected $memberId; /** * @var array custom options for cURL */ - protected $customCurlOptions = null; + protected $customCurlOptions; + /** + * PSR-3 compatible logger + * use only from wrappers methods log* + * @see https://github.com/Seldaek/monolog + * @var \Monolog\Logger + */ + protected $log; /** * Create a object to work with Bitrix24 REST API service * @param bool $isSaveRawResponse - if true raw response from bitrix24 will be available from method getRawResponse, this is debug mode + * @param null|\Monolog\Logger $obLogger - instance of \Monolog\Logger * @throws Bitrix24Exception * @return Bitrix24 */ - public function __construct($isSaveRawResponse = false) + public function __construct($isSaveRawResponse = false, $obLogger = null) { if (!extension_loaded('curl')) { @@ -102,6 +117,21 @@ public function __construct($isSaveRawResponse = false) throw new Bitrix24Exception('isSaveRawResponse flag must be boolean'); } $this->isSaveRawResponse = $isSaveRawResponse; + if($obLogger !== null) + { + /** + * @var \Monolog\Logger + */ + $this->log = clone $obLogger; + } + else + { + // dev/null logger + /** + * @var \Monolog\Logger + */ + $this->log = new Stub(); + } } /** @@ -272,7 +302,6 @@ public function setApplicationScope(array $applicationScope) } } - /** * Get application scope */ @@ -410,6 +439,7 @@ protected function executeRequest($url, array $additionalParameters = array()) curl_setopt_array($curl, $curlOptions); $curlResult = curl_exec($curl); $this->requestInfo = curl_getinfo($curl); + $this->log->debug('cURL request info', array($this->requestInfo)); $curlErrorNumber = curl_errno($curl); // handling network I/O errors if($curlErrorNumber > 0) @@ -430,7 +460,7 @@ protected function executeRequest($url, array $additionalParameters = array()) $jsonResult = json_decode($curlResult, true); unset($curlResult); $jsonErrorCode = json_last_error(); - if(is_null($jsonResult) && (JSON_ERROR_NONE != $jsonErrorCode)) + if(null === $jsonResult && (JSON_ERROR_NONE !== $jsonErrorCode)) { /** * @todo add function json_last_error_msg() @@ -446,19 +476,25 @@ protected function executeRequest($url, array $additionalParameters = array()) * @param string $methodName * @param array $additionalParameters * @throws Bitrix24Exception + * @throws Bitrix24ApiException + * @throws Bitrix24TokenIsInvalid + * @throws Bitrix24TokenIsExpired + * @throws Bitrix24WrongClientException + * @throws Bitrix24MethodNotFoundException + * @throws Bitrix24SecurityException * @return array */ public function call($methodName, array $additionalParameters = array()) { - if(is_null($this->getDomain())) + if(null === $this->getDomain()) { throw new Bitrix24Exception('domain not found, you must call setDomain method before'); } - if(is_null($this->getAccessToken())) + if(null === $this->getAccessToken()) { throw new Bitrix24Exception('access token not found, you must call setAccessToken method before'); } - if(0 == strlen($methodName)) + if('' === $methodName) { throw new Bitrix24Exception('method name not found, you must set method name'); } @@ -473,6 +509,11 @@ public function call($methodName, array $additionalParameters = array()) $isSecureCall = true; } // execute request + $this->log->info('call bitrix24 method', array( + 'BITRIX24_DOMAIN' => $this->domain, + 'METHOD_NAME' => $methodName, + 'METHOD_PARAMETERS' => $additionalParameters + )); $requestResult = $this->executeRequest($url, $additionalParameters); // check errors and throw exception if errors exists $this->handleBitrix24APILevelErrors($requestResult, $methodName); @@ -486,11 +527,11 @@ public function call($methodName, array $additionalParameters = array()) { throw new Bitrix24SecurityException('security signature is corrupted'); } - if(is_null($this->getMemberId())) + if(null === $this->getMemberId()) { throw new Bitrix24Exception('member-id not found, you must call setMemberId method before'); } - if(is_null($this->getApplicationSecret())) + if(null === $this->getApplicationSecret()) { throw new Bitrix24Exception('application secret not found, you must call setApplicationSecret method before'); } @@ -509,7 +550,7 @@ public function call($methodName, array $additionalParameters = array()) $arClearData = json_decode(base64_decode($dataToDecode), true); // handling json_decode errors $jsonErrorCode = json_last_error(); - if(is_null($arClearData) && (JSON_ERROR_NONE != $jsonErrorCode)) + if(null === $arClearData && (JSON_ERROR_NONE !== $jsonErrorCode)) { /** * @todo add function json_last_error_msg() @@ -519,7 +560,7 @@ public function call($methodName, array $additionalParameters = array()) } // merge dirty and clear data unset($arClearData['state']); - $requestResult ["result"] = array_merge($requestResult ["result"], $arClearData); + $requestResult ['result'] = array_merge($requestResult ['result'], $arClearData); } else { @@ -535,6 +576,8 @@ public function call($methodName, array $additionalParameters = array()) * @param $methodName * @return null * @throws Bitrix24ApiException + * @throws Bitrix24TokenIsInvalid + * @throws Bitrix24TokenIsExpired * @throws Bitrix24WrongClientException * @throws Bitrix24MethodNotFoundException */ @@ -548,13 +591,14 @@ protected function handleBitrix24APILevelErrors($arRequestResult, $methodName) { case 'WRONG_CLIENT': throw new Bitrix24WrongClientException($errorMsg); - break; case 'ERROR_METHOD_NOT_FOUND': throw new Bitrix24MethodNotFoundException($errorMsg); - break; + case 'INVALID_TOKEN': + throw new Bitrix24TokenIsInvalid($errorMsg); + case 'EXPIRED_TOKEN': + throw new Bitrix24TokenIsExpired($errorMsg); default: throw new Bitrix24ApiException($errorMsg); - break; } } return null; @@ -578,6 +622,11 @@ public function getRawResponse() * Get new access token * @return array * @throws Bitrix24Exception + * @throws Bitrix24ApiException + * @throws Bitrix24TokenIsInvalid + * @throws Bitrix24TokenIsExpired + * @throws Bitrix24WrongClientException + * @throws Bitrix24MethodNotFoundException */ public function getNewAccessToken() { @@ -588,19 +637,19 @@ public function getNewAccessToken() $applicationScope = $this->getApplicationScope(); $redirectUri = $this->getRedirectUri(); - if(is_null($domain)) + if(null === $domain) { throw new Bitrix24Exception('domain not found, you must call setDomain method before'); } - elseif(is_null($applicationId)) + elseif(null === $applicationId) { throw new Bitrix24Exception('application id not found, you must call setApplicationId method before'); } - elseif(is_null($applicationSecret)) + elseif(null === $applicationSecret) { throw new Bitrix24Exception('application id not found, you must call setApplicationSecret method before'); } - elseif(is_null($refreshToken)) + elseif(null === $refreshToken) { throw new Bitrix24Exception('application id not found, you must call setRefreshToken method before'); } @@ -608,16 +657,16 @@ public function getNewAccessToken() { throw new Bitrix24Exception('application scope not found, you must call setApplicationScope method before'); } - elseif(is_null($redirectUri)) + elseif(null === $redirectUri) { throw new Bitrix24Exception('application redirect URI not found, you must call setRedirectUri method before'); } - $url = 'https://'.$domain."/oauth/token/". - "?client_id=".urlencode($applicationId). - "&grant_type=refresh_token". - "&client_secret=".$applicationSecret. - "&refresh_token=".$refreshToken. + $url = 'https://'.$domain.'/oauth/token/'. + '?client_id='.urlencode($applicationId). + '&grant_type=refresh_token'. + '&client_secret='.$applicationSecret. + '&refresh_token='.$refreshToken. '&scope='.implode(',', array_map('urlencode', array_unique($applicationScope))). '&redirect_uri='.urlencode($redirectUri); $requestResult = $this->executeRequest($url); @@ -626,11 +675,18 @@ public function getNewAccessToken() return $requestResult; } - /** - * Authorize and get first access token - * @return array - * @throws Bitrix24Exception - */ + /** + * Authorize and get first access token + * @param $code + * @return array + * @throws Bitrix24ApiException + * @throws Bitrix24Exception + * @throws Bitrix24IoException + * @throws Bitrix24MethodNotFoundException + * @throws Bitrix24TokenIsExpired + * @throws Bitrix24TokenIsInvalid + * @throws Bitrix24WrongClientException + */ public function getFirstAccessToken($code) { $domain = $this->getDomain(); @@ -640,15 +696,15 @@ public function getFirstAccessToken($code) $applicationScope = $this->getApplicationScope(); $redirectUri = $this->getRedirectUri(); - if(is_null($domain)) + if(null === $domain) { throw new Bitrix24Exception('domain not found, you must call setDomain method before'); } - elseif(is_null($applicationId)) + elseif(null === $applicationId) { throw new Bitrix24Exception('application id not found, you must call setApplicationId method before'); } - elseif(is_null($applicationSecret)) + elseif(null === $applicationSecret) { throw new Bitrix24Exception('application id not found, you must call setApplicationSecret method before'); } @@ -656,18 +712,18 @@ public function getFirstAccessToken($code) { throw new Bitrix24Exception('application scope not found, you must call setApplicationScope method before'); } - elseif(is_null($redirectUri)) + elseif(null === $redirectUri) { throw new Bitrix24Exception('application redirect URI not found, you must call setRedirectUri method before'); } - $url = 'https://'.$domain."/oauth/token/". - "?client_id=".urlencode($applicationId). - "&grant_type=authorization_code". - "&client_secret=".$applicationSecret. + $url = 'https://'.$domain.'/oauth/token/'. + '?client_id='.urlencode($applicationId). + '&grant_type=authorization_code'. + '&client_secret='.$applicationSecret. '&scope='.implode(',', array_map('urlencode', array_unique($applicationScope))). '&redirect_uri='.urlencode($redirectUri). - '&code='.urlencode($_GET['code']); + '&code='.urlencode($code); $requestResult = $this->executeRequest($url); // handling bitrix24 api-level errors @@ -676,9 +732,14 @@ public function getFirstAccessToken($code) } /** - * Сheck is access token expire, сall list of all available api-methods from B24 portal with current access token + * Check is access token expire, call list of all available api-methods from B24 portal with current access token * if we have an error code expired_token then return true else return false * @throws Bitrix24Exception + * @throws Bitrix24ApiException + * @throws Bitrix24TokenIsInvalid + * @throws Bitrix24TokenIsExpired + * @throws Bitrix24WrongClientException + * @throws Bitrix24MethodNotFoundException * @return boolean */ public function isAccessTokenExpire() @@ -687,20 +748,25 @@ public function isAccessTokenExpire() $accessToken = $this->getAccessToken(); $domain = $this->getDomain(); - if(is_null($domain)) + if(null === $domain) { throw new Bitrix24Exception('domain not found, you must call setDomain method before'); } - elseif(is_null($accessToken)) + elseif(null === $accessToken) { throw new Bitrix24Exception('application id not found, you must call setAccessToken method before'); } - $url = 'https://'.$domain."/rest/app.info?auth=".$accessToken; + $url = 'https://'.$domain.'/rest/app.info?auth='.$accessToken; $requestResult = $this->executeRequest($url); - if('expired_token' == $requestResult['error']) + if('expired_token' === $requestResult['error']) { $isTokenExpire = true; } + else + { + // handle other errors + $this->handleBitrix24APILevelErrors($requestResult, 'app.info'); + } return $isTokenExpire; }// end of isTokenExpire @@ -711,16 +777,16 @@ public function isAccessTokenExpire() * @return array * @throws Bitrix24Exception */ - public function getАvailableMethoods($applicationScope = array(), $isFull=false) + public function getAvailableMethods(array $applicationScope = array(), $isFull = false) { $accessToken = $this->getAccessToken(); $domain = $this->getDomain(); - if(is_null($domain)) + if(null === $domain) { throw new Bitrix24Exception('domain not found, you must call setDomain method before'); } - elseif(is_null($accessToken)) + elseif(null === $accessToken) { throw new Bitrix24Exception('application id not found, you must call setAccessToken method before'); } @@ -731,7 +797,7 @@ public function getАvailableMethoods($applicationScope = array(), $isFull=false $showAll = '&full=true'; } $scope=''; - if(is_null($applicationScope)) + if(null === $applicationScope) { $scope = '&scope'; } @@ -739,7 +805,7 @@ public function getАvailableMethoods($applicationScope = array(), $isFull=false { $scope = '&scope='.implode(',', array_map('urlencode', array_unique($applicationScope))); } - $url = 'https://'.$domain."/rest/methods.json?auth=".$accessToken.$showAll.$scope; + $url = 'https://'.$domain.'/rest/methods.json?auth='.$accessToken.$showAll.$scope; $requestResult = $this->executeRequest($url); return $requestResult; } @@ -755,11 +821,11 @@ public function getScope($isFull=false) $accessToken = $this->getAccessToken(); $domain = $this->getDomain(); - if(is_null($domain)) + if(null === $domain) { throw new Bitrix24Exception('domain not found, you must call setDomain method before'); } - elseif(is_null($accessToken)) + elseif(null === $accessToken) { throw new Bitrix24Exception('application id not found, you must call setAccessToken method before'); } @@ -768,8 +834,8 @@ public function getScope($isFull=false) { $showAll = '&full=true'; } - $url = 'https://'.$domain."/rest/scope.json?auth=".$accessToken.$showAll; + $url = 'https://'.$domain.'/rest/scope.json?auth='.$accessToken.$showAll; $requestResult = $this->executeRequest($url); return $requestResult; } -} +} \ No newline at end of file diff --git a/src/bitrix24exception.php b/src/bitrix24exception.php index ee1461d2..7b0fa41b 100644 --- a/src/bitrix24exception.php +++ b/src/bitrix24exception.php @@ -6,8 +6,10 @@ * \Bitrix24Exception — base class * \Bitrix24IoException — I/O network errors * \Bitrix24ApiException — API level errors - * \Bitrix24WrongClientException - Wrong client or application will be deleted from portal - * \Bitrix24MethodNotFoundException - API-method not found + * \Bitrix24WrongClientException — Wrong client or application will be deleted from portal + * \Bitrix24MethodNotFoundException — API-method not found + * \Bitrix24TokenIsInvalid — The access token provided is invalid + * \Bitrix24TokenIsExpired — The access token provided has expired * \Bitrix24SecurityException — Security errors for protected methods */ namespace Bitrix24; @@ -16,4 +18,6 @@ class Bitrix24IoException extends Bitrix24Exception {} class Bitrix24ApiException extends Bitrix24Exception {} class Bitrix24WrongClientException extends Bitrix24ApiException {} class Bitrix24MethodNotFoundException extends Bitrix24ApiException {} +class Bitrix24TokenIsInvalid extends Bitrix24ApiException {} +class Bitrix24TokenIsExpired extends Bitrix24ApiException {} class Bitrix24SecurityException extends Bitrix24Exception {} diff --git a/src/logger/stub.php b/src/logger/stub.php new file mode 100644 index 00000000..78d2dc76 --- /dev/null +++ b/src/logger/stub.php @@ -0,0 +1,130 @@ + Date: Thu, 7 Jan 2016 01:09:23 +0300 Subject: [PATCH 043/647] add debug backtrace for logger, some minor bugfix --- README.md | 45 ++++++++++++++++---- src/bitrix24.php | 107 ++++++++++++++++++++++++----------------------- 2 files changed, 93 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index 15010b2f..9ca4fd47 100644 --- a/README.md +++ b/README.md @@ -4,14 +4,33 @@ bitrix24-php-sdk (unofficial) A powerfull PHP library for the Bitrix24 REST API -[Bitrix24 API documentation](http://dev.1c-bitrix.ru/rest_help/) +[Bitrix24 API documentation - Russian](http://dev.1c-bitrix.ru/rest_help/)
+[Bitrix24 API documentation - English](https://training.bitrix24.com/rest_help/) +## Promo code for new Bitrix24 accounts +- `b24io5gb` — add 5GB on your Bitrix24 +- `b24iousers` — add 12 users on your Bitrix24 + +[Register new Bitrix24 account](https://www.bitrix24.ru/create.php?p=255670) + ## Requirements +- php: >=5.3.2 +- ext-json: * +- ext-curl: * +- Monolog: optional -PHP 5.3 or above ## Example ## ``` php +pushHandler(new StreamHandler('path/to/your.log', Logger::DEBUG)); + + // init lib -$obB24App = new \Bitrix24\Bitrix24(); +$obB24App = new \Bitrix24\Bitrix24(false, $log); $obB24App->setApplicationScope($arParams['B24_APPLICATION_SCOPE']); $obB24App->setApplicationId($arParams['B24_APPLICATION_ID']); $obB24App->setApplicationSecret($arParams['B24_APPLICATION_SECRET']); @@ -28,7 +47,19 @@ $arCurrentB24User = $obB24User->current(); ``` ## Installation ## Add `"mesilov/bitrix24-php-sdk": "dev-master"` to `composer.json` of your application. Or clone repo to your project. -## Support ## -email: -vk: [mesilov.maxim](https://vk.com/mesilov.maxim) -twitter: [@mesilov](https://twitter.com/mesilov) + +## Submitting bugs and feature requests + +Bugs and feature request are tracked on [GitHub](https://github.com/mesilov/bitrix24-php-sdk/issues) + +## License + +bitrix24-php-sdk is licensed under the MIT License - see the `MIT-LICENSE.txt` file for details + +## Author + +Maxim Mesilov - -
+See also the list of [contributors](https://github.com/mesilov/bitrix24-php-sdk/graphs/contributors) which participated in this project. + +## Need custom Bitrix24 application? ## +email: \ No newline at end of file diff --git a/src/bitrix24.php b/src/bitrix24.php index c3cc4eca..4b840674 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -152,15 +152,12 @@ public function getSecuritySignSalt() */ public function setMemberId($memberId) { - if(!empty($memberId)) - { - $this->memberId = $memberId; - return true; - } - else + if('' === $memberId) { throw new Bitrix24Exception('memberId is empty'); } + $this->memberId = $memberId; + return true; } /** @@ -180,15 +177,12 @@ public function getMemberId() */ public function setRedirectUri($redirectUri) { - if(!empty($redirectUri)) - { - $this->redirectUri = $redirectUri; - return true; - } - else + if('' === $redirectUri) { - throw new Bitrix24Exception('redirect URI not set'); + throw new Bitrix24Exception('redirect URI is empty'); } + $this->redirectUri = $redirectUri; + return true; } /** @@ -207,15 +201,12 @@ public function getRedirectUri() */ public function setAccessToken($accessToken) { - if(!empty($accessToken)) + if('' === $accessToken) { + throw new Bitrix24Exception('access token is empty'); + } $this->accessToken = $accessToken; return true; - } - else - { - throw new Bitrix24Exception('access token not set'); - } } /** @@ -235,15 +226,12 @@ public function getAccessToken() */ public function setRefreshToken($refreshToken) { - if(!empty($refreshToken)) - { - $this->refreshToken = $refreshToken; - return true; - } - else + if('' === $refreshToken) { - throw new Bitrix24Exception('refresh token not set'); + throw new Bitrix24Exception('refresh token is empty'); } + $this->refreshToken = $refreshToken; + return true; } /** @@ -263,15 +251,12 @@ public function getRefreshToken() */ public function setDomain($domain) { - if(!empty($domain)) + if('' === $domain) { - $this->domain = $domain; - return true; - } - else - { - throw new Bitrix24Exception('domain not set'); + throw new Bitrix24Exception('domain is empty'); } + $this->domain = $domain; + return true; } /** @@ -318,15 +303,12 @@ public function getApplicationScope() */ public function setApplicationId($applicationId) { - if(!empty($applicationId)) - { - $this->applicationId = $applicationId; - return true; - } - else + if('' === $applicationId) { - throw new Bitrix24Exception('application id not set'); + throw new Bitrix24Exception('application id is empty'); } + $this->applicationId = $applicationId; + return true; }// end of SetApplicationId /** @@ -346,15 +328,12 @@ public function getApplicationId() */ public function setApplicationSecret($applicationSecret) { - if(!empty($applicationSecret)) + if('' === $applicationSecret) { - $this->applicationSecret = $applicationSecret; - return true; - } - else - { - throw new Bitrix24Exception('application secret not set'); + throw new Bitrix24Exception('application secret is empty'); } + $this->applicationSecret = $applicationSecret; + return true; } /** @@ -516,7 +495,7 @@ public function call($methodName, array $additionalParameters = array()) )); $requestResult = $this->executeRequest($url, $additionalParameters); // check errors and throw exception if errors exists - $this->handleBitrix24APILevelErrors($requestResult, $methodName); + $this->handleBitrix24APILevelErrors($requestResult, $methodName, $additionalParameters); // handling security sign for secure api-call if($isSecureCall) { @@ -574,6 +553,7 @@ public function call($methodName, array $additionalParameters = array()) * Handling bitrix24 api-level errors * @param $arRequestResult * @param $methodName + * @param array $additionalParameters * @return null * @throws Bitrix24ApiException * @throws Bitrix24TokenIsInvalid @@ -581,11 +561,34 @@ public function call($methodName, array $additionalParameters = array()) * @throws Bitrix24WrongClientException * @throws Bitrix24MethodNotFoundException */ - protected function handleBitrix24APILevelErrors($arRequestResult, $methodName) + protected function handleBitrix24APILevelErrors($arRequestResult, $methodName, array $additionalParameters = array()) { if (array_key_exists('error', $arRequestResult)) { - $errorMsg = sprintf('%s - %s in call [ %s ]', $arRequestResult['error'], (isset($arRequestResult['error_description']) ? $arRequestResult['error_description'] : ''), $methodName); + $errorMsg = sprintf('%s - %s in call [%s] for domain [%s]', + $arRequestResult['error'], + (array_key_exists('error_description', $arRequestResult) ? $arRequestResult['error_description'] : ''), + $methodName, + $this->getDomain()); + $this->log->error($errorMsg, array( + // response + 'REQUEST_RESULT' => $arRequestResult, + // query + 'METHOD_NAME' => $methodName, + 'ADDITIONAL_PARAMETERS' => $additionalParameters, + // portal specific settings + 'B24_DOMAIN' => $this->getDomain(), + 'B24_MEMBER_ID' => $this->getMemberId(), + 'B24_ACCESS_TOKEN' => $this->getAccessToken(), + 'B24_REFRESH_TOKEN' => $this->getRefreshToken(), + // application settings + 'APPLICATION_SCOPE' => $this->getApplicationScope(), + 'APPLICATION_ID' => $this->getApplicationId(), + 'APPLICATION_SECRET' => $this->getApplicationSecret(), + 'REDIRECT_URI' => $this->getRedirectUri(), + // network + 'RAW_REQUEST' => $this->getRawRequest(), + 'CURL_REQUEST_INFO' => $this->getRequestInfo())); // throw specific API-level exceptions switch(strtoupper(trim($arRequestResult['error']))) { @@ -653,7 +656,7 @@ public function getNewAccessToken() { throw new Bitrix24Exception('application id not found, you must call setRefreshToken method before'); } - elseif(empty($applicationScope)) + elseif(0 === count($applicationScope)) { throw new Bitrix24Exception('application scope not found, you must call setApplicationScope method before'); } @@ -708,7 +711,7 @@ public function getFirstAccessToken($code) { throw new Bitrix24Exception('application id not found, you must call setApplicationSecret method before'); } - elseif(empty($applicationScope)) + elseif(0 === count($applicationScope)) { throw new Bitrix24Exception('application scope not found, you must call setApplicationScope method before'); } From 5d4896d760d0e29c494ff0e0b43412ac54826ae8 Mon Sep 17 00:00:00 2001 From: Damiano Porta Date: Thu, 7 Jan 2016 13:26:34 +0100 Subject: [PATCH 044/647] Fix the name of the call inside fields() --- src/classes/crm/deal/deal.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/classes/crm/deal/deal.php b/src/classes/crm/deal/deal.php index 70788073..63cbb263 100644 --- a/src/classes/crm/deal/deal.php +++ b/src/classes/crm/deal/deal.php @@ -46,7 +46,7 @@ public function delete($dealId) public function fields() { $fullResult = $this->client->call( - 'crm.invoice.fields' + 'crm.deal.fields' ); return $fullResult; } From 7f76dff39b6b94aec9d4ff9357e702d70ce48095 Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Sat, 9 Jan 2016 18:54:36 +0300 Subject: [PATCH 045/647] add tests for syntax errors --- composer.json | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 42913353..53ff4d31 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,16 @@ "ext-curl": "*", "psr/log": "^1.0" }, + "require-dev": { + "jakub-onderka/php-parallel-lint": "0.9", + "jakub-onderka/php-console-highlighter": "~0.3" + }, "autoload": { "classmap": ["src/"] + }, + "scripts": { + "test": [ + "parallel-lint . --exclude vendor" + ] } -} +} \ No newline at end of file From 00def7b324f2821864a938abb2c804cc989892f3 Mon Sep 17 00:00:00 2001 From: Maxim Mesilov Date: Sat, 9 Jan 2016 19:25:22 +0300 Subject: [PATCH 046/647] update .gitignore, add vendor folder --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6d12c5fc..2d53a013 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -/.idea* \ No newline at end of file +/.idea* +vendor From e514c7b47c51a20d74e5dbbcc5c2bf738844772c Mon Sep 17 00:00:00 2001 From: Maxim Mesilov Date: Sat, 9 Jan 2016 19:26:14 +0300 Subject: [PATCH 047/647] add .travis.yml --- .travis.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..b308ee1c --- /dev/null +++ b/.travis.yml @@ -0,0 +1,24 @@ +language: php + +php: + - 5.3.3 + - 5.4 + - 5.5 + - 5.6 + - 7.0 + - hhvm + +sudo: false + +cache: + directories: + - vendor + - $HOME/.composer/cache + +before_script: + - composer self-update + - composer install --no-interaction --prefer-source --dev + - composer require jakub-onderka/php-console-highlighter 0.3 + +script: + - ./parallel-lint --exclude vendor . From a2f13a71b3d20e5b9fd3980945899c862a2e7a09 Mon Sep 17 00:00:00 2001 From: Maxim Mesilov Date: Sat, 9 Jan 2016 19:29:19 +0300 Subject: [PATCH 048/647] fix path for parallel-lint --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b308ee1c..f7030b5f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,4 +21,4 @@ before_script: - composer require jakub-onderka/php-console-highlighter 0.3 script: - - ./parallel-lint --exclude vendor . + parallel-lint . --exclude vendor From 5fa1b018c81210e46552edb0795f431662fe5547 Mon Sep 17 00:00:00 2001 From: Maxim Mesilov Date: Sat, 9 Jan 2016 19:38:32 +0300 Subject: [PATCH 049/647] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f7030b5f..b7b64b8d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,4 +21,4 @@ before_script: - composer require jakub-onderka/php-console-highlighter 0.3 script: - parallel-lint . --exclude vendor + composer test From 4df76efde88119bd573992e4aa59f301d266c7eb Mon Sep 17 00:00:00 2001 From: Maxim Mesilov Date: Sat, 9 Jan 2016 19:42:13 +0300 Subject: [PATCH 050/647] fix readme doc add a travis bage --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9ca4fd47..19624990 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -bitrix24-php-sdk (unofficial) +bitrix24-php-sdk [![Build Status](https://travis-ci.org/mesilov/bitrix24-php-sdk.svg?branch=master)](https://travis-ci.org/mesilov/bitrix24-php-sdk) ================ [![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/mesilov/bitrix24-php-sdk?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![License](https://poser.pugx.org/mesilov/bitrix24-php-sdk/license.svg)](https://packagist.org/packages/mesilov/bitrix24-php-sdk) [![Total Downloads](https://poser.pugx.org/mesilov/bitrix24-php-sdk/downloads.svg)](https://packagist.org/packages/mesilov/bitrix24-php-sdk) @@ -62,4 +62,4 @@ Maxim Mesilov - -
See also the list of [contributors](https://github.com/mesilov/bitrix24-php-sdk/graphs/contributors) which participated in this project. ## Need custom Bitrix24 application? ## -email: \ No newline at end of file +email: From f2f01604ced034c3182e69fec4b2b7fdb1012f06 Mon Sep 17 00:00:00 2001 From: yugene Date: Wed, 13 Jan 2016 00:43:22 +0300 Subject: [PATCH 051/647] crm.status.fields crm.status.entity.types crm.status.entity.items --- src/classes/crm/status/status.php | 51 +++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 src/classes/crm/status/status.php diff --git a/src/classes/crm/status/status.php b/src/classes/crm/status/status.php new file mode 100644 index 00000000..daac3df0 --- /dev/null +++ b/src/classes/crm/status/status.php @@ -0,0 +1,51 @@ +client->call( + 'crm.status.fields' + ); + return $fullResult; + } + + /** + * get list of dictionary types + * @link https://dev.1c-bitrix.ru/rest_help/crm/auxiliary/status/crm_status_entity_types.php + * @return array + */ + public function entityTypes() + { + $fullResult = $this->client->call( + 'crm.status.entity.types' + ); + return $fullResult; + } + + /** + * get dictionary data + * @link https://dev.1c-bitrix.ru/rest_help/crm/auxiliary/status/crm_status_entity_items.php + * @param string $entityId + * @return array + */ + public function entityItems($entityId) + { + $fullResult = $this->client->call( + 'crm.status.entity.items', + array( + 'entityId' => $entityId + ) + ); + return $fullResult; + } +} From e21fdc6029c322b086fc97ef22070de03a8c4a84 Mon Sep 17 00:00:00 2001 From: Damiano Porta Date: Sat, 23 Jan 2016 13:23:22 +0100 Subject: [PATCH 052/647] Added delete() method --- src/classes/crm/contact/contact.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/classes/crm/contact/contact.php b/src/classes/crm/contact/contact.php index 66ac1dff..dc510dd6 100644 --- a/src/classes/crm/contact/contact.php +++ b/src/classes/crm/contact/contact.php @@ -65,6 +65,22 @@ public function get($bitrix24UserId) return $fullResult; } + /** + * Deletes the specified contact + * @link http://dev.1c-bitrix.ru/rest_help/crm/contacts/crm_contact_delete.php + * @param integer $bitrix24UserId contact identifier + * @return array + * @throws Bitrix24Exception + */ + public function delete($bitrix24UserId) + { + $fullResult = $this->client->call( + 'crm.contact.delete', + array('id' => $bitrix24UserId) + ); + return $fullResult; + } + /** * get list of contact fields with description * @link http://dev.1c-bitrix.ru/rest_help/crm/contacts/crm_contact_fields.php From 42fb215dfc07011b912609b147a2cfbebef95dbf Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 24 Jan 2016 01:27:25 +0300 Subject: [PATCH 053/647] add phpunit --- .gitignore | 2 + .travis.yml | 1 - composer.json | 7 +- phpunit.xml.dist | 16 ++ src/bitrix24.php | 17 +- src/contracts/ibitrix24.php | 257 ++++++++++++++++++ src/stub/bitrix24.php | 319 +++++++++++++++++++++++ src/{logger/stub.php => stub/logger.php} | 6 +- tests/bootstrap.php | 11 + tests/src/Bitrix24Test.php | 71 +++++ 10 files changed, 696 insertions(+), 11 deletions(-) create mode 100644 phpunit.xml.dist create mode 100644 src/contracts/ibitrix24.php create mode 100644 src/stub/bitrix24.php rename src/{logger/stub.php => stub/logger.php} (91%) create mode 100644 tests/bootstrap.php create mode 100644 tests/src/Bitrix24Test.php diff --git a/.gitignore b/.gitignore index 2d53a013..84873cd7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ /.idea* vendor +composer.phar +composer.lock \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index b7b64b8d..09f80ff6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,6 @@ cache: before_script: - composer self-update - composer install --no-interaction --prefer-source --dev - - composer require jakub-onderka/php-console-highlighter 0.3 script: composer test diff --git a/composer.json b/composer.json index 53ff4d31..25207370 100644 --- a/composer.json +++ b/composer.json @@ -19,14 +19,17 @@ }, "require-dev": { "jakub-onderka/php-parallel-lint": "0.9", - "jakub-onderka/php-console-highlighter": "~0.3" + "jakub-onderka/php-console-highlighter": "~0.3", + "phpunit/phpunit": "~4.8", + "phpunit/phpunit-mock-objects": "2.3.0" }, "autoload": { "classmap": ["src/"] }, "scripts": { "test": [ - "parallel-lint . --exclude vendor" + "parallel-lint . --exclude vendor --no-colors", + "phpunit --colors=always --verbose --debug" ] } } \ No newline at end of file diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 00000000..e3c57095 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,16 @@ + + + + + + tests/src/ + + + + + src/ + + + diff --git a/src/bitrix24.php b/src/bitrix24.php index 4b840674..41aa9b8f 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -1,13 +1,16 @@ * @copyright 2013 - 2016 Mesilov Maxim */ -class Bitrix24 +class Bitrix24 implements iBitrix24 { /** * SDK version @@ -102,11 +105,11 @@ class Bitrix24 /** * Create a object to work with Bitrix24 REST API service * @param bool $isSaveRawResponse - if true raw response from bitrix24 will be available from method getRawResponse, this is debug mode - * @param null|\Monolog\Logger $obLogger - instance of \Monolog\Logger + * @param null|LoggerInterface $obLogger - instance of \Monolog\Logger * @throws Bitrix24Exception * @return Bitrix24 */ - public function __construct($isSaveRawResponse = false, $obLogger = null) + public function __construct($isSaveRawResponse = false, LoggerInterface $obLogger = null) { if (!extension_loaded('curl')) { @@ -130,7 +133,7 @@ public function __construct($isSaveRawResponse = false, $obLogger = null) /** * @var \Monolog\Logger */ - $this->log = new Stub(); + $this->log = new Logger(); } } @@ -156,6 +159,10 @@ public function setMemberId($memberId) { throw new Bitrix24Exception('memberId is empty'); } + elseif(null === $memberId) + { + throw new Bitrix24Exception('memberId is null'); + } $this->memberId = $memberId; return true; } diff --git a/src/contracts/ibitrix24.php b/src/contracts/ibitrix24.php new file mode 100644 index 00000000..57be576f --- /dev/null +++ b/src/contracts/ibitrix24.php @@ -0,0 +1,257 @@ + value1, CURLOPT_XXX2 => value2,...) + * @return bool + */ + public function setCustomCurlOptions($options); + + /** + * Return raw request, contain all cURL options array and API query. Data available after you try to call method call + * numbers of array keys is const of cURL module. Example: CURLOPT_RETURNTRANSFER = 19913 + * @return array | null + */ + public function getRawRequest(); + + /** + * Return result from function curl_getinfo. Data available after you try to call method call + * @return array | null + */ + public function getRequestInfo(); + + /** + * Return additional parameters of last api-call. Data available after you try to call method call + * @return array | null + */ + public function getMethodParameters(); + + /** + * Execute Bitrix24 REST API method + * @param string $methodName + * @param array $additionalParameters + * @throws Bitrix24Exception + * @throws Bitrix24ApiException + * @throws Bitrix24TokenIsInvalid + * @throws Bitrix24TokenIsExpired + * @throws Bitrix24WrongClientException + * @throws Bitrix24MethodNotFoundException + * @throws Bitrix24SecurityException + * @return array + */ + public function call($methodName, array $additionalParameters = array()); + + /** + * Get raw response from Bitrix24 before json_decode call, method available only in debug mode. + * To activate debug mode you must before set to true flag isSaveRawResponse in class construct + * @throws Bitrix24Exception + * @return string + */ + public function getRawResponse(); + + /** + * Get new access token + * @return array + * @throws Bitrix24Exception + * @throws Bitrix24ApiException + * @throws Bitrix24TokenIsInvalid + * @throws Bitrix24TokenIsExpired + * @throws Bitrix24WrongClientException + * @throws Bitrix24MethodNotFoundException + */ + public function getNewAccessToken(); + + /** + * Authorize and get first access token + * @param $code + * @return array + * @throws Bitrix24ApiException + * @throws Bitrix24Exception + * @throws Bitrix24IoException + * @throws Bitrix24MethodNotFoundException + * @throws Bitrix24TokenIsExpired + * @throws Bitrix24TokenIsInvalid + * @throws Bitrix24WrongClientException + */ + public function getFirstAccessToken($code); + + /** + * Check is access token expire, call list of all available api-methods from B24 portal with current access token + * if we have an error code expired_token then return true else return false + * @throws Bitrix24Exception + * @throws Bitrix24ApiException + * @throws Bitrix24TokenIsInvalid + * @throws Bitrix24TokenIsExpired + * @throws Bitrix24WrongClientException + * @throws Bitrix24MethodNotFoundException + * @return boolean + */ + public function isAccessTokenExpire(); + + /** + * Get list of all methods available for current application + * @param array | null $applicationScope + * @param bool $isFull + * @return array + * @throws Bitrix24Exception + */ + public function getAvailableMethods(array $applicationScope = array(), $isFull = false); + + /** + * get list of scope for current application from bitrix24 api + * @param bool $isFull + * @throws Bitrix24Exception + * @return array + */ + public function getScope($isFull=false); +} \ No newline at end of file diff --git a/src/stub/bitrix24.php b/src/stub/bitrix24.php new file mode 100644 index 00000000..4c0a295d --- /dev/null +++ b/src/stub/bitrix24.php @@ -0,0 +1,319 @@ + value1, CURLOPT_XXX2 => value2,...) + * @return bool + */ + public function setCustomCurlOptions($options) + { + } + + /** + * Return raw request, contain all cURL options array and API query. Data available after you try to call method call + * numbers of array keys is const of cURL module. Example: CURLOPT_RETURNTRANSFER = 19913 + * @return array | null + */ + public function getRawRequest() + { + } + + /** + * Return result from function curl_getinfo. Data available after you try to call method call + * @return array | null + */ + public function getRequestInfo() + { + } + + /** + * Return additional parameters of last api-call. Data available after you try to call method call + * @return array | null + */ + public function getMethodParameters() + { + } + + /** + * Execute Bitrix24 REST API method + * @param string $methodName + * @param array $additionalParameters + * @throws Bitrix24Exception + * @throws Bitrix24ApiException + * @throws Bitrix24TokenIsInvalid + * @throws Bitrix24TokenIsExpired + * @throws Bitrix24WrongClientException + * @throws Bitrix24MethodNotFoundException + * @throws Bitrix24SecurityException + * @return array + */ + public function call($methodName, array $additionalParameters = array()) + { + } + + /** + * Get raw response from Bitrix24 before json_decode call, method available only in debug mode. + * To activate debug mode you must before set to true flag isSaveRawResponse in class construct + * @throws Bitrix24Exception + * @return string + */ + public function getRawResponse() + { + } + + /** + * Get new access token + * @return array + * @throws Bitrix24Exception + * @throws Bitrix24ApiException + * @throws Bitrix24TokenIsInvalid + * @throws Bitrix24TokenIsExpired + * @throws Bitrix24WrongClientException + * @throws Bitrix24MethodNotFoundException + */ + public function getNewAccessToken() + { + } + + /** + * Authorize and get first access token + * @param $code + * @return array + * @throws Bitrix24ApiException + * @throws Bitrix24Exception + * @throws Bitrix24IoException + * @throws Bitrix24MethodNotFoundException + * @throws Bitrix24TokenIsExpired + * @throws Bitrix24TokenIsInvalid + * @throws Bitrix24WrongClientException + */ + public function getFirstAccessToken($code) + { + } + + /** + * Check is access token expire, call list of all available api-methods from B24 portal with current access token + * if we have an error code expired_token then return true else return false + * @throws Bitrix24Exception + * @throws Bitrix24ApiException + * @throws Bitrix24TokenIsInvalid + * @throws Bitrix24TokenIsExpired + * @throws Bitrix24WrongClientException + * @throws Bitrix24MethodNotFoundException + * @return boolean + */ + public function isAccessTokenExpire() + { + } + + /** + * Get list of all methods available for current application + * @param array | null $applicationScope + * @param bool $isFull + * @return array + * @throws Bitrix24Exception + */ + public function getAvailableMethods(array $applicationScope = array(), $isFull = false) + { + } + + /** + * get list of scope for current application from bitrix24 api + * @param bool $isFull + * @throws Bitrix24Exception + * @return array + */ + public function getScope($isFull=false) + { + } +} + diff --git a/src/logger/stub.php b/src/stub/logger.php similarity index 91% rename from src/logger/stub.php rename to src/stub/logger.php index 78d2dc76..34389a0f 100644 --- a/src/logger/stub.php +++ b/src/stub/logger.php @@ -1,12 +1,12 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +require __DIR__ . "/../vendor/autoload.php"; +date_default_timezone_set('UTC'); diff --git a/tests/src/Bitrix24Test.php b/tests/src/Bitrix24Test.php new file mode 100644 index 00000000..fa2e18f7 --- /dev/null +++ b/tests/src/Bitrix24Test.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24; + +use Bitrix24\Stub\Logger as Bitrix24StubLogger; +/** + * Class Bitrix24Test + * @package Bitrix24 + */ +class Bitrix24Test extends \PHPUnit_Framework_TestCase +{ + /** + * @covers Bitrix24::__construct + */ + public function testConstructorWithFirstArgumentIsNotBoolean() + { + $this->setExpectedException('\Bitrix24\Bitrix24Exception'); + $obBitrix24 = new Bitrix24(array()); + } + /** + * @covers Bitrix24::__construct + */ + public function testConstructorWithoutSecondArgument() + { + $obBitrix24 = new Bitrix24(false); + } + /** + * @covers Bitrix24::__construct + */ + public function testConstructorWithStubLogger() + { + $obBitrix24 = new Bitrix24(false, new Bitrix24StubLogger()); + } + /** + * @covers Bitrix24::setMemberId + */ + public function testSetMemberIdWithValidArgument() + { + $obBitrix24 = new Bitrix24(false, new Bitrix24StubLogger()); + $result = $obBitrix24->setMemberId('valid_member_id'); + $this->assertTrue($result); + } + /** + * @covers Bitrix24::setMemberId + */ + public function testSetMemberIdWithNullArgument() + { + $this->setExpectedException('\Bitrix24\Bitrix24Exception'); + $obBitrix24 = new Bitrix24(false, new Bitrix24StubLogger()); + $result = $obBitrix24->setMemberId(null); + $this->assertTrue($result); + } + /** + * @covers Bitrix24::setMemberId + */ + public function testSetMemberIdWithEmptyStringArgument() + { + $this->setExpectedException('\Bitrix24\Bitrix24Exception'); + $obBitrix24 = new Bitrix24(false, new Bitrix24StubLogger()); + $result = $obBitrix24->setMemberId(''); + $this->assertTrue($result); + } +} \ No newline at end of file From a6a6e38fcb57d02609b9b0bd34450be6f94f20b9 Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Wed, 27 Jan 2016 21:19:57 +0300 Subject: [PATCH 054/647] Add rich IM notifications --- src/classes/im/attach/attach.php | 119 ++++++++++++++ src/classes/im/attach/iattach.php | 44 ++++++ src/classes/im/attach/iattachitem.php | 30 ++++ src/classes/im/attach/item/delimiter.php | 60 +++++++ src/classes/im/attach/item/file.php | 67 ++++++++ src/classes/im/attach/item/grid.php | 114 +++++++++++++ src/classes/im/attach/item/image.php | 60 +++++++ src/classes/im/attach/item/link.php | 75 +++++++++ src/classes/im/attach/item/user.php | 68 ++++++++ src/classes/im/notify.php | 193 +++++++++++++++++++++++ src/presets/scope.php | 13 +- 11 files changed, 842 insertions(+), 1 deletion(-) create mode 100644 src/classes/im/attach/attach.php create mode 100644 src/classes/im/attach/iattach.php create mode 100644 src/classes/im/attach/iattachitem.php create mode 100644 src/classes/im/attach/item/delimiter.php create mode 100644 src/classes/im/attach/item/file.php create mode 100644 src/classes/im/attach/item/grid.php create mode 100644 src/classes/im/attach/item/image.php create mode 100644 src/classes/im/attach/item/link.php create mode 100644 src/classes/im/attach/item/user.php create mode 100644 src/classes/im/notify.php diff --git a/src/classes/im/attach/attach.php b/src/classes/im/attach/attach.php new file mode 100644 index 00000000..fefc0b54 --- /dev/null +++ b/src/classes/im/attach/attach.php @@ -0,0 +1,119 @@ + and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Bitrix24\Im\Attach; +use Bitrix24\Bitrix24Entity; +use Bitrix24\Bitrix24Exception; +use Bitrix24\Presets\Im\Fields as B24ImFields; +use Bitrix24\Im\Attach\iAttachItem; + +/** + * Class Attach + * @package Bitrix24\Im\Attach + */ +class Attach implements iAttach +{ + /** + * @var string + */ + const CHAT = "CHAT"; + /** + * @var int $id Unix timestamp + */ + protected $id; + /** + * @var string $color hex color see iAttach interface + */ + protected $color; + /** + * @var array + */ + protected $attachItems; + /** + * Attach constructor. + * @param null | int $id Unix timestamp + * @param null | string $color hex color see iAttach interface + */ + public function __construct($id = null, $color = null) + { + if(null === $id) + { + $this->id = time(); + } + + if (self::CHAT !== $color) + { + if(null === $color) + { + $this->color = $this->setStatusNormal(); + } + } + } + + /** + * @param iAttachItem $attachItem + */ + public function add(iAttachItem $attachItem) + { + $this->attachItems[] = clone $attachItem; + } + + /** + * @return array + */ + public function getData() + { + return array( + 'ID' => $this->id, + 'BLOCKS' => $this->getAttachList(), + 'COLOR' => $this->color + + ); + } + + /** + * @return array + */ + private function getAttachList() + { + $arResult = array(); + /** + * @var $obAttachItem iAttachItem + */ + foreach($this->attachItems as $cnt => $obAttachItem) + { + $arResult[][$obAttachItem->getAttachTypeCode()] = $obAttachItem->getAttachData(); + } + return $arResult; + } + + /** + * @return mixed + */ + public function setStatusNormal() + { + $this->color = self::STATUS_NORMAL; + } + + /** + * @return mixed + */ + public function setStatusAttention() + { + $this->color = self::STATUS_ATTENTION; + } + + /** + * @return mixed + */ + public function setStatusProblem() + { + $this->color = self::STATUS_PROBLEM; + } +} \ No newline at end of file diff --git a/src/classes/im/attach/iattach.php b/src/classes/im/attach/iattach.php new file mode 100644 index 00000000..20464fd7 --- /dev/null +++ b/src/classes/im/attach/iattach.php @@ -0,0 +1,44 @@ + and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Bitrix24\Im\Attach; +/** + * Interface iAttach + * @package Bitrix24\Im\Attach + */ +interface iAttach +{ + /** + * @var string + */ + const STATUS_NORMAL = "#aac337"; + /** + * @var string + */ + const STATUS_ATTENTION = "#e8a441"; + /** + * @var string + */ + const STATUS_PROBLEM = "#df532d"; + + /** + * @return mixed + */ + public function setStatusNormal(); + + /** + * @return mixed + */ + public function setStatusAttention(); + + /** + * @return mixed + */ + public function setStatusProblem(); +} diff --git a/src/classes/im/attach/iattachitem.php b/src/classes/im/attach/iattachitem.php new file mode 100644 index 00000000..61b0e6e7 --- /dev/null +++ b/src/classes/im/attach/iattachitem.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Bitrix24\Im\Attach; +use Bitrix24\Bitrix24Entity; +use Bitrix24\Bitrix24Exception; +use Bitrix24\Presets\Im\Fields as B24ImFields; + +/** + * Interface iAttachItem + * @package Bitrix24\Im\Attach + */ +interface iAttachItem +{ + /** + * @return mixed + */ + public function getAttachData(); + + /** + * @return string + */ + public function getAttachTypeCode(); +} \ No newline at end of file diff --git a/src/classes/im/attach/item/delimiter.php b/src/classes/im/attach/item/delimiter.php new file mode 100644 index 00000000..5f7e5969 --- /dev/null +++ b/src/classes/im/attach/item/delimiter.php @@ -0,0 +1,60 @@ + and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Bitrix24\Im\Attach\Item; +use Bitrix24\Im\Attach\iAttachItem; +/** + * Class Delimiter + * @package Bitrix24\Im\Attach\Item + */ +class Delimiter implements iAttachItem +{ + /** + * @var string + */ + const ATTACH_TYPE_CODE = 'DELIMITER'; + /** + * @var + */ + protected $color; + /** + * @var + */ + protected $size; + + /** + * Delimiter constructor. + * @param $size + * @param $color + */ + public function __construct($size = null, $color = null) + { + $this->size = $size; + $this->color = $color; + } + + /** + * @return array + */ + public function getAttachData() + { + return array( + 'SIZE' => $this->size, + 'COLOR' => $this->color, + ); + } + + /** + * @return string + */ + public function getAttachTypeCode() + { + return self::ATTACH_TYPE_CODE; + } +} \ No newline at end of file diff --git a/src/classes/im/attach/item/file.php b/src/classes/im/attach/item/file.php new file mode 100644 index 00000000..4306e86f --- /dev/null +++ b/src/classes/im/attach/item/file.php @@ -0,0 +1,67 @@ + and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Bitrix24\Im\Attach\Item; +use Bitrix24\Im\Attach\iAttachItem; +/** + * Class File + * @package Bitrix24\Im\Attach\Item + */ +class File implements iAttachItem +{ + /** + * @var string + */ + const ATTACH_TYPE_CODE = 'FILE'; + /** + * @var + */ + protected $name; + /** + * @var + */ + protected $link; + /** + * @var + */ + protected $size; + + /** + * Image constructor. + * @param $name + * @param $link + * @param $size + */ + public function __construct($link, $name, $size) + { + $this->name = $name; + $this->link = $link; + $this->size = $size; + } + + /** + * @return array + */ + public function getAttachData() + { + return array( + 'NAME' => $this->name, + 'LINK' => $this->link, + 'SIZE' => $this->size, + ); + } + + /** + * @return string + */ + public function getAttachTypeCode() + { + return self::ATTACH_TYPE_CODE; + } +} \ No newline at end of file diff --git a/src/classes/im/attach/item/grid.php b/src/classes/im/attach/item/grid.php new file mode 100644 index 00000000..ea3159bc --- /dev/null +++ b/src/classes/im/attach/item/grid.php @@ -0,0 +1,114 @@ + and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Bitrix24\Im\Attach\Item; +use Bitrix24\Im\Attach\iAttachItem; +/** + * Class Grid + * @package Bitrix24\Im\Attach\Item + */ +class Grid implements iAttachItem +{ + /** + * @var string + */ + const ATTACH_TYPE_CODE = 'GRID'; + /** + * @var array + */ + protected $arGridItems = array(); + + /** + * Grid constructor. + */ + public function __construct() + { + } + + /** + * @param $name + * @param $value + * @param null $color + * @param null $link + * @param null $chatId + * @param null $userId + */ + public function addBlockItem($name, $value, $color = null, $link = null, $chatId = null, $userId = null) + { + $this->arGridItems[] = array( + 'DISPLAY' => 'BLOCK', + 'NAME' => $name, + 'VALUE' => $value, + 'COLOR' => $color, + 'LINK' => $link, + 'CHAT_ID' => $chatId, + 'USER_ID' => $userId + ); + } + + /** + * @param $name + * @param $value + * @param $width + * @param null $color + * @param null $link + * @param null $chatId + * @param null $userId + */ + public function addLineItem($name, $value, $width, $color = null, $link = null, $chatId = null, $userId = null) + { + $this->arGridItems[] = array( + 'DISPLAY' => 'LINE', + 'NAME' => $name, + 'VALUE' => $value, + 'WIDTH' => $width, + 'COLOR' => $color, + 'LINK' => $link, + 'CHAT_ID' => $chatId, + 'USER_ID' => $userId + ); + } + + /** + * @param $name + * @param $value + * @param null $color + * @param null $link + * @param null $chatId + * @param null $userId + */ + public function addColumnItem($name, $value, $width, $color = null, $link = null, $chatId = null, $userId = null) + { + $this->arGridItems[] = array( + 'DISPLAY' => 'COLUMN', + 'NAME' => $name, + 'VALUE' => $value, + 'WIDTH' => $width, + 'COLOR' => $color, + 'LINK' => $link, + 'CHAT_ID' => $chatId, + 'USER_ID' => $userId + ); + } + /** + * @return array + */ + public function getAttachData() + { + return $this->arGridItems; + } + + /** + * @return string + */ + public function getAttachTypeCode() + { + return self::ATTACH_TYPE_CODE; + } +} \ No newline at end of file diff --git a/src/classes/im/attach/item/image.php b/src/classes/im/attach/item/image.php new file mode 100644 index 00000000..6a0ce147 --- /dev/null +++ b/src/classes/im/attach/item/image.php @@ -0,0 +1,60 @@ + and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Bitrix24\Im\Attach\Item; +use Bitrix24\Im\Attach\iAttachItem; +/** + * Class Image + * @package Bitrix24\Im\Attach\Item + */ +class Image implements iAttachItem +{ + /** + * @var string + */ + const ATTACH_TYPE_CODE = 'IMAGE'; + /** + * @var + */ + protected $name; + /** + * @var + */ + protected $link; + + /** + * Image constructor. + * @param $name + * @param $link + */ + public function __construct($name, $link) + { + $this->name = $name; + $this->link = $link; + } + + /** + * @return array + */ + public function getAttachData() + { + return array( + 'NAME' => $this->name, + 'LINK' => $this->link + ); + } + + /** + * @return string + */ + public function getAttachTypeCode() + { + return self::ATTACH_TYPE_CODE; + } +} \ No newline at end of file diff --git a/src/classes/im/attach/item/link.php b/src/classes/im/attach/item/link.php new file mode 100644 index 00000000..69ff3510 --- /dev/null +++ b/src/classes/im/attach/item/link.php @@ -0,0 +1,75 @@ + and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Bitrix24\Im\Attach\Item; +use Bitrix24\Im\Attach\iAttachItem; + +/** + * Class Link + * @package Bitrix24\Im\Attach\Item + */ +class Link implements iAttachItem +{ + /** + * @var string + */ + const ATTACH_TYPE_CODE = 'LINK'; + /** + * @var + */ + protected $name; + /** + * @var + */ + protected $description; + /** + * @var + */ + protected $link; + /** + * @var string + */ + protected $preview; + + /** + * Link constructor. + * @param $name string required + * @param $link string required + * @param $description string + * @param $preview string required + */ + public function __construct($name, $link, $description, $preview) + { + $this->name = $name; + $this->link = $link; + $this->description = $description; + $this->preview = $preview; + } + + /** + * @return array + */ + public function getAttachData() + { + return array( + 'NAME' => $this->name, + 'DESC' => $this->description, + 'LINK' => $this->link, + 'PREVIEW' => $this->preview + ); + } + + /** + * @return string + */ + public function getAttachTypeCode() + { + return self::ATTACH_TYPE_CODE; + } +} \ No newline at end of file diff --git a/src/classes/im/attach/item/user.php b/src/classes/im/attach/item/user.php new file mode 100644 index 00000000..0872e2c9 --- /dev/null +++ b/src/classes/im/attach/item/user.php @@ -0,0 +1,68 @@ + and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Bitrix24\Im\Attach\Item; +use Bitrix24\Im\Attach\iAttachItem; + +/** + * Class User + * @package Bitrix24\Im\Attach\Item + */ +class User implements iAttachItem +{ + /** + * @var string + */ + const ATTACH_TYPE_CODE = 'USER'; + /** + * @var + */ + protected $userName; + /** + * @var + */ + protected $avatarUrl; + /** + * @var + */ + protected $userLink; + + /** + * User constructor. + * @param $userName string required + * @param $avatarUrl string + * @param $userLink string + */ + public function __construct($userName, $avatarUrl = null, $userLink = null) + { + $this->userName = $userName; + $this->avatarUrl = $avatarUrl; + $this->userLink = $userLink; + } + + /** + * @return array + */ + public function getAttachData() + { + return array( + 'NAME' => $this->userName, + 'AVATAR' => $this->avatarUrl, + 'LINK' => $this->userLink + ); + } + + /** + * @return string + */ + public function getAttachTypeCode() + { + return self::ATTACH_TYPE_CODE; + } +} \ No newline at end of file diff --git a/src/classes/im/notify.php b/src/classes/im/notify.php new file mode 100644 index 00000000..ca5273ea --- /dev/null +++ b/src/classes/im/notify.php @@ -0,0 +1,193 @@ + and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Bitrix24\Im; +use Bitrix24\Bitrix24Entity; +use Bitrix24\Bitrix24Exception; +use Bitrix24\Presets\Im\Fields as B24ImFields; +use Bitrix24\Im\Attach\Attach; + +/** + * Class Notify + * @package Bitrix24\Im + */ +class Notify extends Bitrix24Entity +{ + /** + * @param $userId + * @param $message + * @param string $tag + * @param string $subTag + * @param Attach|null $attachObject + * @return array + * @throws Bitrix24Exception + * @throws \Bitrix24\Bitrix24SecurityException + * @throws \Bitrix24\Bitrix24Exception + * @throws \Bitrix24\Bitrix24ApiException + * @throws \Bitrix24\Bitrix24TokenIsInvalid + * @throws \Bitrix24\Bitrix24TokenIsExpired + * @throws \Bitrix24\Bitrix24WrongClientException + * @throws \Bitrix24\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Bitrix24SecurityException + */ + public function addPersonal($userId, $message, $tag = '', $subTag = '', Attach $attachObject = null) + { + if(null === $userId) + { + throw new Bitrix24Exception('user id is null'); + } + elseif(null === $message) + { + throw new Bitrix24Exception('message is null'); + } + elseif(null === $attachObject) + { + $attachObject = new Attach(); + } + $fullResult = $this->client->call( + 'im.notify.personal.add', + array( + 'user_id' => (int) $userId, + 'message' => (string) $message, + 'tag' => (string) $tag, + 'sub_tag' => (string) $subTag, + 'attach' => $attachObject->getData() + ) + ); + return $fullResult; + } + + /** + * @param $userId + * @param $message + * @param string $tag + * @param string $subTag + * @param Attach|null $attachObject + * @return array + * @throws Bitrix24Exception + * @throws \Bitrix24\Bitrix24SecurityException + * @throws \Bitrix24\Bitrix24Exception + * @throws \Bitrix24\Bitrix24ApiException + * @throws \Bitrix24\Bitrix24TokenIsInvalid + * @throws \Bitrix24\Bitrix24TokenIsExpired + * @throws \Bitrix24\Bitrix24WrongClientException + * @throws \Bitrix24\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Bitrix24SecurityException + */ + public function addSystem($userId, $message, $tag = '', $subTag = '', Attach $attachObject = null) + { + if(null === $userId) + { + throw new Bitrix24Exception('user id is null'); + } + elseif(null === $message) + { + throw new Bitrix24Exception('message is null'); + } + elseif(null === $attachObject) + { + $attachObject = new Attach(); + } + $fullResult = $this->client->call( + 'im.notify.system.add', + array( + 'user_id' => (int) $userId, + 'message' => (string) $message, + 'tag' => (string) $tag, + 'sub_tag' => (string) $subTag, + 'attach' => $attachObject->getData() + ) + ); + return $fullResult; + } + + /** + * @param $id + * @return array + * @throws Bitrix24Exception + * @throws \Bitrix24\Bitrix24SecurityException + * @throws \Bitrix24\Bitrix24Exception + * @throws \Bitrix24\Bitrix24ApiException + * @throws \Bitrix24\Bitrix24TokenIsInvalid + * @throws \Bitrix24\Bitrix24TokenIsExpired + * @throws \Bitrix24\Bitrix24WrongClientException + * @throws \Bitrix24\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Bitrix24SecurityException + */ + public function deleteById($id) + { + if(null === $id) + { + throw new Bitrix24Exception('id is null'); + } + $fullResult = $this->client->call( + 'im.notify.delete', + array( + 'id' => (int) $id + ) + ); + return $fullResult; + } + + /** + * @param $tag + * @return array + * @throws Bitrix24Exception + * @throws \Bitrix24\Bitrix24SecurityException + * @throws \Bitrix24\Bitrix24Exception + * @throws \Bitrix24\Bitrix24ApiException + * @throws \Bitrix24\Bitrix24TokenIsInvalid + * @throws \Bitrix24\Bitrix24TokenIsExpired + * @throws \Bitrix24\Bitrix24WrongClientException + * @throws \Bitrix24\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Bitrix24SecurityException + */ + public function deleteByTag($tag) + { + if(null === $tag) + { + throw new Bitrix24Exception('tag is null'); + } + $fullResult = $this->client->call( + 'im.notify.delete', + array( + 'tag' => (string) $tag + ) + ); + return $fullResult; + } + + /** + * @param $subTag + * @return array + * @throws Bitrix24Exception + * @throws \Bitrix24\Bitrix24SecurityException + * @throws \Bitrix24\Bitrix24Exception + * @throws \Bitrix24\Bitrix24ApiException + * @throws \Bitrix24\Bitrix24TokenIsInvalid + * @throws \Bitrix24\Bitrix24TokenIsExpired + * @throws \Bitrix24\Bitrix24WrongClientException + * @throws \Bitrix24\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Bitrix24SecurityException + */ + public function deleteBySubTag($subTag) + { + if(null === $subTag) + { + throw new Bitrix24Exception('subTag is null'); + } + $fullResult = $this->client->call( + 'im.notify.delete', + array( + 'sub_tag' => (string) $subTag + ) + ); + return $fullResult; + } +} \ No newline at end of file diff --git a/src/presets/scope.php b/src/presets/scope.php index ec49c7c8..3bfeb6ca 100644 --- a/src/presets/scope.php +++ b/src/presets/scope.php @@ -1,6 +1,17 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ namespace Bitrix24\Presets; - +/** + * Class Scope + * @package Bitrix24\Presets + */ class Scope { const DEPARTMENT = 'department'; From f61d2c8941fe4422e342a7d3437e9bc56e70a57c Mon Sep 17 00:00:00 2001 From: Maxim Mesilov Date: Thu, 28 Jan 2016 01:21:30 +0300 Subject: [PATCH 055/647] fix ssl error in CI test https://blog.travis-ci.com/upcoming_ubuntu_11_10_migration/ --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index 09f80ff6..e512dcfa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,11 @@ php: - 5.6 - 7.0 - hhvm + +matrix: + allow_failures: + - php: 5.3.3 + - php: hhvm sudo: false From f1b441bf46fe343fe2d21370eed7ddc1a333987b Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Thu, 4 Feb 2016 23:57:01 +0300 Subject: [PATCH 056/647] add a RetriesToConnectCount and RetriesToConnectTimeout methods --- src/bitrix24.php | 223 +++++++++++++++++++++++----- src/classes/crm/contact/contact.php | 2 +- src/contracts/ibitrix24.php | 26 ++++ tests/src/Bitrix24Test.php | 54 +++++++ 4 files changed, 269 insertions(+), 36 deletions(-) diff --git a/src/bitrix24.php b/src/bitrix24.php index 41aa9b8f..46cee506 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -13,49 +13,42 @@ class Bitrix24 implements iBitrix24 { /** - * SDK version + * @var string SDK version */ const VERSION = '1.0'; /** - * access token - * @var string + * @var string access token */ protected $accessToken; /** - * refresh token - * @var string + * @var string refresh token */ protected $refreshToken; /** - * domain - * @var string + * @var string domain */ protected $domain; /** - * scope - * @var array + * @var array scope */ protected $applicationScope = array(); /** - * application id - * @var string + * @var string application id */ protected $applicationId; /** - * application secret - * @var string + * @var string application secret */ protected $applicationSecret; /** - * raw request, contain all cURL options array and API query - * @var array + * @var array raw request, contain all cURL options array and API query */ protected $rawRequest; @@ -65,8 +58,7 @@ class Bitrix24 implements iBitrix24 protected $methodParameters; /** - * request info data structure акщь curl_getinfo function - * @var array + * @var array request info data structure акщь curl_getinfo function */ protected $requestInfo; @@ -94,19 +86,31 @@ class Bitrix24 implements iBitrix24 * @var array custom options for cURL */ protected $customCurlOptions; + /** - * PSR-3 compatible logger - * use only from wrappers methods log* * @see https://github.com/Seldaek/monolog - * @var \Monolog\Logger + * @var \Monolog\Logger PSR-3 compatible logger, use only from wrappers methods log* */ protected $log; + /** + * @var integer CURL request count retries + */ + protected $retriesToConnectCount; + + /** + * @var integer retries to connect timeout in microseconds + */ + protected $retriesToConnectTimeout; + /** * Create a object to work with Bitrix24 REST API service + * * @param bool $isSaveRawResponse - if true raw response from bitrix24 will be available from method getRawResponse, this is debug mode * @param null|LoggerInterface $obLogger - instance of \Monolog\Logger + * * @throws Bitrix24Exception + * * @return Bitrix24 */ public function __construct($isSaveRawResponse = false, LoggerInterface $obLogger = null) @@ -135,11 +139,14 @@ public function __construct($isSaveRawResponse = false, LoggerInterface $obLogge */ $this->log = new Logger(); } + $this->setRetriesToConnectCount(1); + $this->setRetriesToConnectTimeout(1000000); } /** * Get a random string to sign protected api-call. Use salt for argument "state" in secure api-call * random string is a result of mt_rand function + * * @return int */ public function getSecuritySignSalt() @@ -149,9 +156,12 @@ public function getSecuritySignSalt() /** * Set member ID — portal GUID + * * @param string $memberId + * * @throws Bitrix24Exception - * @return true; + * + * @return true */ public function setMemberId($memberId) { @@ -169,6 +179,7 @@ public function setMemberId($memberId) /** * Get memeber ID + * * @return string | null */ public function getMemberId() @@ -178,8 +189,11 @@ public function getMemberId() /** * Set redirect URI + * * @param string $redirectUri + * * @throws Bitrix24Exception + * * @return true; */ public function setRedirectUri($redirectUri) @@ -194,17 +208,22 @@ public function setRedirectUri($redirectUri) /** * Get redirect URI + * * @return string | null */ public function getRedirectUri() { return $this->redirectUri; } + /** * Set access token + * * @param string $accessToken + * * @throws Bitrix24Exception - * @return true; + * + * @return true */ public function setAccessToken($accessToken) { @@ -218,6 +237,7 @@ public function setAccessToken($accessToken) /** * Get access token + * * @return string | null */ public function getAccessToken() @@ -227,8 +247,11 @@ public function getAccessToken() /** * Set refresh token + * * @param $refreshToken + * * @throws Bitrix24Exception + * * @return true; */ public function setRefreshToken($refreshToken) @@ -243,6 +266,7 @@ public function setRefreshToken($refreshToken) /** * Get refresh token + * * @return string */ public function getRefreshToken() @@ -252,8 +276,11 @@ public function getRefreshToken() /** * Set domain + * * @param $domain + * * @throws Bitrix24Exception + * * @return true; */ public function setDomain($domain) @@ -268,6 +295,7 @@ public function setDomain($domain) /** * Get domain + * * @return string | null */ public function getDomain() @@ -277,8 +305,11 @@ public function getDomain() /** * Set application scope + * * @param array $applicationScope + * * @return boolean + * * @throws Bitrix24Exception */ public function setApplicationScope(array $applicationScope) @@ -296,6 +327,8 @@ public function setApplicationScope(array $applicationScope) /** * Get application scope + * + * @return string */ public function getApplicationScope() { @@ -304,8 +337,11 @@ public function getApplicationScope() /** * Set application id + * * @param string $applicationId + * * @throws Bitrix24Exception + * * @return true; */ public function setApplicationId($applicationId) @@ -320,6 +356,7 @@ public function setApplicationId($applicationId) /** * Get application id + * * @return string */ public function getApplicationId() @@ -329,8 +366,11 @@ public function getApplicationId() /** * Set application secret + * * @param string $applicationSecret + * * @throws Bitrix24Exception + * * @return true; */ public function setApplicationSecret($applicationSecret) @@ -345,6 +385,7 @@ public function setApplicationSecret($applicationSecret) /** * Get application secret + * * @return string */ public function getApplicationSecret() @@ -354,8 +395,11 @@ public function getApplicationSecret() /** * Set custom cURL options, overriding default ones + * * @link http://php.net/manual/en/function.curl-setopt.php + * * @param array $options - array(CURLOPT_XXX => value1, CURLOPT_XXX2 => value2,...) + * * @return bool */ public function setCustomCurlOptions($options) @@ -368,6 +412,7 @@ public function setCustomCurlOptions($options) /** * Return raw request, contain all cURL options array and API query. Data available after you try to call method call * numbers of array keys is const of cURL module. Example: CURLOPT_RETURNTRANSFER = 19913 + * * @return array | null */ public function getRawRequest() @@ -377,6 +422,7 @@ public function getRawRequest() /** * Return result from function curl_getinfo. Data available after you try to call method call + * * @return array | null */ public function getRequestInfo() @@ -386,6 +432,7 @@ public function getRequestInfo() /** * Return additional parameters of last api-call. Data available after you try to call method call + * * @return array | null */ public function getMethodParameters() @@ -395,13 +442,26 @@ public function getMethodParameters() /** * Execute a request API to Bitrix24 using cURL + * * @param string $url * @param array $additionalParameters + * * @throws Bitrix24Exception + * * @return array */ protected function executeRequest($url, array $additionalParameters = array()) { + $retryableErrorCodes = array( + CURLE_COULDNT_RESOLVE_HOST, + CURLE_COULDNT_CONNECT, + CURLE_HTTP_NOT_FOUND, + CURLE_READ_ERROR, + CURLE_OPERATION_TIMEOUTED, + CURLE_HTTP_POST_ERROR, + CURLE_SSL_CONNECT_ERROR, + ); + $curlOptions = array( CURLOPT_RETURNTRANSFER => true, CURLINFO_HEADER_OUT => true, @@ -423,20 +483,33 @@ protected function executeRequest($url, array $additionalParameters = array()) $this->rawRequest = $curlOptions; $curl = curl_init(); curl_setopt_array($curl, $curlOptions); - $curlResult = curl_exec($curl); - $this->requestInfo = curl_getinfo($curl); - $this->log->debug('cURL request info', array($this->requestInfo)); - $curlErrorNumber = curl_errno($curl); - // handling network I/O errors - if($curlErrorNumber > 0) - { - $errorMsg = curl_error($curl).PHP_EOL.'cURL error code: '.$curlErrorNumber.PHP_EOL; - curl_close($curl); - throw new Bitrix24IoException($errorMsg); - } - else - { + + $curlResult = false; + $retriesCnt = $this->retriesToConnectCount; + while($retriesCnt--){ + $this->log->debug(sprintf('try [%s] to connect to host [%s]', $retriesCnt, $this->getDomain())); + $curlResult = curl_exec($curl); + // handling network I/O errors + if(false === $curlResult) + { + $curlErrorNumber = curl_errno($curl); + $errorMsg = sprintf('in try[%s] cURL error (code %s): %s'.PHP_EOL, $retriesCnt, $curlErrorNumber, curl_error($curl)); + if (false === in_array($curlErrorNumber, $retryableErrorCodes, true) || !$retriesCnt) { + $this->log->error($errorMsg); + curl_close($curl); + throw new Bitrix24IoException($errorMsg); + } + else + { + $this->log->warning($errorMsg); + } + usleep($this->getRetriesToConnectTimeout()); + continue; + } + $this->requestInfo = curl_getinfo($curl); + $this->log->debug('cURL request info', array($this->requestInfo)); curl_close($curl); + break; } if(true === $this->isSaveRawResponse) { @@ -459,8 +532,10 @@ protected function executeRequest($url, array $additionalParameters = array()) /** * Execute Bitrix24 REST API method + * * @param string $methodName * @param array $additionalParameters + * * @throws Bitrix24Exception * @throws Bitrix24ApiException * @throws Bitrix24TokenIsInvalid @@ -468,6 +543,7 @@ protected function executeRequest($url, array $additionalParameters = array()) * @throws Bitrix24WrongClientException * @throws Bitrix24MethodNotFoundException * @throws Bitrix24SecurityException + * * @return array */ public function call($methodName, array $additionalParameters = array()) @@ -558,10 +634,13 @@ public function call($methodName, array $additionalParameters = array()) /** * Handling bitrix24 api-level errors + * * @param $arRequestResult * @param $methodName * @param array $additionalParameters + * * @return null + * * @throws Bitrix24ApiException * @throws Bitrix24TokenIsInvalid * @throws Bitrix24TokenIsExpired @@ -613,10 +692,13 @@ protected function handleBitrix24APILevelErrors($arRequestResult, $methodName, a } return null; } + /** * Get raw response from Bitrix24 before json_decode call, method available only in debug mode. * To activate debug mode you must before set to true flag isSaveRawResponse in class construct + * * @throws Bitrix24Exception + * * @return string */ public function getRawResponse() @@ -630,7 +712,9 @@ public function getRawResponse() /** * Get new access token + * * @return array + * * @throws Bitrix24Exception * @throws Bitrix24ApiException * @throws Bitrix24TokenIsInvalid @@ -687,8 +771,11 @@ public function getNewAccessToken() /** * Authorize and get first access token + * * @param $code + * * @return array + * * @throws Bitrix24ApiException * @throws Bitrix24Exception * @throws Bitrix24IoException @@ -744,12 +831,14 @@ public function getFirstAccessToken($code) /** * Check is access token expire, call list of all available api-methods from B24 portal with current access token * if we have an error code expired_token then return true else return false + * * @throws Bitrix24Exception * @throws Bitrix24ApiException * @throws Bitrix24TokenIsInvalid * @throws Bitrix24TokenIsExpired * @throws Bitrix24WrongClientException * @throws Bitrix24MethodNotFoundException + * * @return boolean */ public function isAccessTokenExpire() @@ -782,9 +871,12 @@ public function isAccessTokenExpire() /** * Get list of all methods available for current application + * * @param array | null $applicationScope * @param bool $isFull + * * @return array + * * @throws Bitrix24Exception */ public function getAvailableMethods(array $applicationScope = array(), $isFull = false) @@ -822,8 +914,11 @@ public function getAvailableMethods(array $applicationScope = array(), $isFull = /** * get list of scope for current application from bitrix24 api + * * @param bool $isFull + * * @throws Bitrix24Exception + * * @return array */ public function getScope($isFull=false) @@ -848,4 +943,62 @@ public function getScope($isFull=false) $requestResult = $this->executeRequest($url); return $requestResult; } + + /** + * set CURL request count retries + * @param $retriesCnt + * + * @return boolean + * + * @throws Bitrix24Exception + */ + public function setRetriesToConnectCount($retriesCnt = 1) + { + $this->log->debug(sprintf('set retries to connect count %s', $retriesCnt)); + if(!is_int($retriesCnt)) + { + throw new Bitrix24Exception('retries to connect count must be an integer'); + } + $this->retriesToConnectCount = (int) $retriesCnt; + return true; + } + + /** + * set retries to connect timeout in microseconds + * @param int $microseconds + + * @return bool + + * @throws Bitrix24Exception + */ + public function setRetriesToConnectTimeout($microseconds = 1000000) + { + $this->log->debug(sprintf('set retries to connect count %s', $microseconds)); + if(!is_numeric($microseconds)) + { + throw new Bitrix24Exception('retries to connect count must be an integer'); + } + $this->retriesToConnectTimeout = $microseconds; + return true; + } + + /** + * get CURL request count retries + * + * @return int + */ + public function getRetriesToConnectCount() + { + return $this->retriesToConnectCount; + } + + /** + * get retries to connect timeout in microseconds + * + * @return mixed + */ + public function getRetriesToConnectTimeout() + { + return $this->retriesToConnectTimeout; + } } \ No newline at end of file diff --git a/src/classes/crm/contact/contact.php b/src/classes/crm/contact/contact.php index dc510dd6..ded8e1d3 100644 --- a/src/classes/crm/contact/contact.php +++ b/src/classes/crm/contact/contact.php @@ -80,7 +80,7 @@ public function delete($bitrix24UserId) ); return $fullResult; } - + /** * get list of contact fields with description * @link http://dev.1c-bitrix.ru/rest_help/crm/contacts/crm_contact_fields.php diff --git a/src/contracts/ibitrix24.php b/src/contracts/ibitrix24.php index 57be576f..31f63566 100644 --- a/src/contracts/ibitrix24.php +++ b/src/contracts/ibitrix24.php @@ -254,4 +254,30 @@ public function getAvailableMethods(array $applicationScope = array(), $isFull = * @return array */ public function getScope($isFull=false); + + /** + * set CURL request count retries + * @param $retriesCnt + * @return boolean + */ + public function setRetriesToConnectCount($retriesCnt = 1); + + /** + * set retries to connect timeout in microseconds + * @param $microseconds + * @return boolean + */ + public function setRetriesToConnectTimeout($microseconds = 1000000); + + /** + * get CURL request count retries + * @return int + */ + public function getRetriesToConnectCount(); + + /** + * get retries to connect timeout in microseconds + * @return mixed + */ + public function getRetriesToConnectTimeout(); } \ No newline at end of file diff --git a/tests/src/Bitrix24Test.php b/tests/src/Bitrix24Test.php index fa2e18f7..fd92d4a2 100644 --- a/tests/src/Bitrix24Test.php +++ b/tests/src/Bitrix24Test.php @@ -68,4 +68,58 @@ public function testSetMemberIdWithEmptyStringArgument() $result = $obBitrix24->setMemberId(''); $this->assertTrue($result); } + /** + * @covers Bitrix24::setRetriesToConnectCount + */ + public function testSetRetriesToConnectCountWithNull() + { + $this->setExpectedException('\Bitrix24\Bitrix24Exception'); + $obBitrix24 = new Bitrix24(false, new Bitrix24StubLogger()); + $result = $obBitrix24->setRetriesToConnectCount(null); + } + /** + * @covers Bitrix24::setRetriesToConnectCount + */ + public function testSetRetriesToConnectCountWithEmptyArgs() + { + $obBitrix24 = new Bitrix24(false, new Bitrix24StubLogger()); + $result = $obBitrix24->setRetriesToConnectCount(); + $this->assertTrue($result); + } + /** + * @covers Bitrix24::setRetriesToConnectCount + */ + public function testSetRetriesToConnectCountWithValidArgs() + { + $obBitrix24 = new Bitrix24(false, new Bitrix24StubLogger()); + $result = $obBitrix24->setRetriesToConnectCount(1); + $this->assertTrue($result); + } + /** + * @covers Bitrix24::setRetriesToConnectTimeout + */ + public function testSetRetriesToConnectTimeoutWithNull() + { + $this->setExpectedException('\Bitrix24\Bitrix24Exception'); + $obBitrix24 = new Bitrix24(false, new Bitrix24StubLogger()); + $result = $obBitrix24->setRetriesToConnectTimeout(null); + } + /** + * @covers Bitrix24::setRetriesToConnectTimeout + */ + public function testSetRetriesToConnectTimeoutWithEmptyArgs() + { + $obBitrix24 = new Bitrix24(false, new Bitrix24StubLogger()); + $result = $obBitrix24->setRetriesToConnectTimeout(); + $this->assertTrue($result); + } + /** + * @covers Bitrix24::setRetriesToConnectTimeout + */ + public function testSetRetriesToConnectTimeoutWithValidArgs() + { + $obBitrix24 = new Bitrix24(false, new Bitrix24StubLogger()); + $result = $obBitrix24->setRetriesToConnectTimeout(1000000); + $this->assertTrue($result); + } } \ No newline at end of file From 5ca663456a4ece889f553364ee8a29062996e448 Mon Sep 17 00:00:00 2001 From: Aracon Date: Sun, 6 Mar 2016 11:19:34 +0300 Subject: [PATCH 057/647] Fixed PHP Notice --- src/bitrix24.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitrix24.php b/src/bitrix24.php index 46cee506..85404863 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -857,7 +857,7 @@ public function isAccessTokenExpire() } $url = 'https://'.$domain.'/rest/app.info?auth='.$accessToken; $requestResult = $this->executeRequest($url); - if('expired_token' === $requestResult['error']) + if(isset($requestResult['error']) && ('expired_token' === $requestResult['error'])) { $isTokenExpire = true; } @@ -1001,4 +1001,4 @@ public function getRetriesToConnectTimeout() { return $this->retriesToConnectTimeout; } -} \ No newline at end of file +} From 508c838ccab0bb5a018705f0ef77ed1ba7accc90 Mon Sep 17 00:00:00 2001 From: Maksim Borodov Date: Tue, 8 Mar 2016 14:14:51 +0300 Subject: [PATCH 058/647] fix not work method --- src/classes/task/commentitem.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/classes/task/commentitem.php b/src/classes/task/commentitem.php index 3176bb26..b16b123d 100644 --- a/src/classes/task/commentitem.php +++ b/src/classes/task/commentitem.php @@ -65,7 +65,11 @@ public function get($taskId, $commentItemId) */ public function add($taskId, $fields) { - $result = $this->client->call('task.commentitem.add', array($taskId, array($fields))); + $result = $this->client->call('task.commentitem.add', + array( + 'TASKID' => $taskId, + 'arFields' => $fields + )); return $result; } @@ -113,4 +117,4 @@ public function isActionAllowed($taskId, $commentItemId, $actionId) $result = $this->client->call('task.commentitem.isactionallowed', array($taskId, $commentItemId, $actionId)); return $result; } -} \ No newline at end of file +} From ade79c30c58553af2c80529a1e8522b05859e66d Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Fri, 8 Apr 2016 00:43:25 +0300 Subject: [PATCH 059/647] add class Chat, remove class Stub\Logger --- composer.json | 2 +- src/bitrix24.php | 7 +- src/classes/bitrix24entity.php | 7 +- src/classes/im/chat.php | 289 ++++++++++++++++++++++++++++++ src/stub/bitrix24.php | 109 ++++++++++- src/stub/logger.php | 130 -------------- tests/src/Bitrix24Test.php | 23 +-- tests/src/classes/im/chatTest.php | 268 +++++++++++++++++++++++++++ 8 files changed, 683 insertions(+), 152 deletions(-) create mode 100644 src/classes/im/chat.php delete mode 100644 src/stub/logger.php create mode 100644 tests/src/classes/im/chatTest.php diff --git a/composer.json b/composer.json index 25207370..dcd28c60 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,7 @@ "scripts": { "test": [ "parallel-lint . --exclude vendor --no-colors", - "phpunit --colors=always --verbose --debug" + "phpunit --colors=always --verbose" ] } } \ No newline at end of file diff --git a/src/bitrix24.php b/src/bitrix24.php index 85404863..9584d773 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -2,7 +2,8 @@ namespace Bitrix24; use Bitrix24\Contracts\iBitrix24; -use Bitrix24\Stub\Logger; + +use Psr\Log\NullLogger; use Psr\Log\LoggerInterface; /** @@ -137,7 +138,7 @@ public function __construct($isSaveRawResponse = false, LoggerInterface $obLogge /** * @var \Monolog\Logger */ - $this->log = new Logger(); + $this->log = new NullLogger(); } $this->setRetriesToConnectCount(1); $this->setRetriesToConnectTimeout(1000000); @@ -1001,4 +1002,4 @@ public function getRetriesToConnectTimeout() { return $this->retriesToConnectTimeout; } -} +} \ No newline at end of file diff --git a/src/classes/bitrix24entity.php b/src/classes/bitrix24entity.php index a2615167..8fbd828e 100644 --- a/src/classes/bitrix24entity.php +++ b/src/classes/bitrix24entity.php @@ -1,6 +1,7 @@ client = $client; } diff --git a/src/classes/im/chat.php b/src/classes/im/chat.php new file mode 100644 index 00000000..3fb2195b --- /dev/null +++ b/src/classes/im/chat.php @@ -0,0 +1,289 @@ + and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Bitrix24\Im; +use Bitrix24\Bitrix24Entity; +use Bitrix24\Bitrix24Exception; +use Bitrix24\Presets\Im\Fields as B24ImFields; +use Bitrix24\Im\Attach\Attach; + +/** + * Class Chat + * @package Bitrix24\Im + */ +class Chat extends Bitrix24Entity +{ + /** + * create new chat + * + * @param string $title + * @param string $description + * @param string $color + * @param string $message + * @param array $users + * @param string $avatarImgInBase64 + * @param bool $isOpen + * + * @throws Bitrix24Exception + * @throws \Bitrix24\Bitrix24SecurityException + * @throws \Bitrix24\Bitrix24Exception + * @throws \Bitrix24\Bitrix24ApiException + * @throws \Bitrix24\Bitrix24TokenIsInvalid + * @throws \Bitrix24\Bitrix24TokenIsExpired + * @throws \Bitrix24\Bitrix24WrongClientException + * @throws \Bitrix24\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Bitrix24SecurityException + * + * @return array + */ + public function add($title, $description='', $color ='', $message = '', array $users = array(), $avatarImgInBase64 = null, $isOpen = false) + { + $arParams = array( + 'title' => (string) $title, + 'description' => (string) $description, + 'color' => (string) $color, + 'message' => (string) $message, + 'users' => $users, + 'avatar' => $avatarImgInBase64, + ); + + if($isOpen) + { + $arParams['type'] = 'OPEN'; + } + return $this->client->call('im.chat.add', $arParams); + } + + /** + * delete chat + * + * @param int $chatId + * + * @return array + * + * @throws Bitrix24Exception + * @throws \Bitrix24\Bitrix24SecurityException + * @throws \Bitrix24\Bitrix24Exception + * @throws \Bitrix24\Bitrix24ApiException + * @throws \Bitrix24\Bitrix24TokenIsInvalid + * @throws \Bitrix24\Bitrix24TokenIsExpired + * @throws \Bitrix24\Bitrix24WrongClientException + * @throws \Bitrix24\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Bitrix24SecurityException + */ + public function delete($chatId) + { + return $this->client->call('im.chat.delete', array( + 'chat_id' => (int) $chatId + )); + } + + /** + * set chat owner + * + * @param $chatId + * @param $userId + * + * @return array + * + * @throws Bitrix24Exception + * @throws \Bitrix24\Bitrix24SecurityException + * @throws \Bitrix24\Bitrix24Exception + * @throws \Bitrix24\Bitrix24ApiException + * @throws \Bitrix24\Bitrix24TokenIsInvalid + * @throws \Bitrix24\Bitrix24TokenIsExpired + * @throws \Bitrix24\Bitrix24WrongClientException + * @throws \Bitrix24\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Bitrix24SecurityException + */ + public function setOwner($chatId, $userId) + { + return $this->client->call('im.chat.setOwner', array( + 'chat_id' => (int) $chatId, + 'user_id' => (int) $userId + )); + } + + /** + * update color + * + * @param int $chatId + * @param string $newColor + * + * @return array + * + * @throws Bitrix24Exception + * @throws \Bitrix24\Bitrix24SecurityException + * @throws \Bitrix24\Bitrix24Exception + * @throws \Bitrix24\Bitrix24ApiException + * @throws \Bitrix24\Bitrix24TokenIsInvalid + * @throws \Bitrix24\Bitrix24TokenIsExpired + * @throws \Bitrix24\Bitrix24WrongClientException + * @throws \Bitrix24\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Bitrix24SecurityException + */ + public function updateColor($chatId, $newColor) + { + return $this->client->call('im.chat.updateColor', array( + 'chat_id' => (int) $chatId, + 'color' => (string) $newColor + )); + } + + /** + * update title + * + * @param int $chatId + * @param string $newTitle + * + * @return array + * + * @throws Bitrix24Exception + * @throws \Bitrix24\Bitrix24SecurityException + * @throws \Bitrix24\Bitrix24Exception + * @throws \Bitrix24\Bitrix24ApiException + * @throws \Bitrix24\Bitrix24TokenIsInvalid + * @throws \Bitrix24\Bitrix24TokenIsExpired + * @throws \Bitrix24\Bitrix24WrongClientException + * @throws \Bitrix24\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Bitrix24SecurityException + */ + public function updateTitle($chatId, $newTitle) + { + return $this->client->call('im.chat.updateTitle', array( + 'chat_id' => (int) $chatId, + 'title' => (string) $newTitle + )); + } + + /** + * update avatar + * + * @param int $chatId + * @param string $avatarImgInBase64 + * + * @return array + * + * @throws Bitrix24Exception + * @throws \Bitrix24\Bitrix24SecurityException + * @throws \Bitrix24\Bitrix24Exception + * @throws \Bitrix24\Bitrix24ApiException + * @throws \Bitrix24\Bitrix24TokenIsInvalid + * @throws \Bitrix24\Bitrix24TokenIsExpired + * @throws \Bitrix24\Bitrix24WrongClientException + * @throws \Bitrix24\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Bitrix24SecurityException + */ + public function updateAvatar($chatId, $avatarImgInBase64) + { + return $this->client->call('im.chat.updateAvatar', array( + 'chat_id' => (int) $chatId, + 'avatar' => (string) $avatarImgInBase64 + )); + } + + + /** + * send typing + * + * @param int $chatId + * + * @return array + * + * @throws Bitrix24Exception + * @throws \Bitrix24\Bitrix24SecurityException + * @throws \Bitrix24\Bitrix24Exception + * @throws \Bitrix24\Bitrix24ApiException + * @throws \Bitrix24\Bitrix24TokenIsInvalid + * @throws \Bitrix24\Bitrix24TokenIsExpired + * @throws \Bitrix24\Bitrix24WrongClientException + * @throws \Bitrix24\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Bitrix24SecurityException + */ + public function sendTyping($chatId) + { + return $this->client->call('im.chat.sendTyping', array( + 'chat_id' => (int) $chatId + )); + } + + /** + * delete user from chat + * + * @param $chatId + * @param $userId + * + * @return array + * + * @throws Bitrix24Exception + * @throws \Bitrix24\Bitrix24SecurityException + * @throws \Bitrix24\Bitrix24Exception + * @throws \Bitrix24\Bitrix24ApiException + * @throws \Bitrix24\Bitrix24TokenIsInvalid + * @throws \Bitrix24\Bitrix24TokenIsExpired + * @throws \Bitrix24\Bitrix24WrongClientException + * @throws \Bitrix24\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Bitrix24SecurityException + */ + public function userDelete($chatId, $userId) + { + return $this->client->call('im.chat.user.delete', array( + 'chat_id' => (int) $chatId, + 'user_id' => (int) $userId + )); + } + + /** + * + * @param $chatId + * @param array $arNewUsers + * + * @return array + * + * @throws Bitrix24Exception + * @throws \Bitrix24\Bitrix24SecurityException + * @throws \Bitrix24\Bitrix24Exception + * @throws \Bitrix24\Bitrix24ApiException + * @throws \Bitrix24\Bitrix24TokenIsInvalid + * @throws \Bitrix24\Bitrix24TokenIsExpired + * @throws \Bitrix24\Bitrix24WrongClientException + * @throws \Bitrix24\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Bitrix24SecurityException */ + public function userAdd($chatId, array $arNewUsers = array()) + { + return $this->client->call('im.chat.user.add', array( + 'chat_id' => (int) $chatId, + 'user_id' => $arNewUsers + )); + } + + /** + * get user list in chat + * + * @param $chatId + * + * @return array + * + * @throws Bitrix24Exception + * @throws \Bitrix24\Bitrix24SecurityException + * @throws \Bitrix24\Bitrix24Exception + * @throws \Bitrix24\Bitrix24ApiException + * @throws \Bitrix24\Bitrix24TokenIsInvalid + * @throws \Bitrix24\Bitrix24TokenIsExpired + * @throws \Bitrix24\Bitrix24WrongClientException + * @throws \Bitrix24\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Bitrix24SecurityException + */ + public function userList($chatId) + { + return $this->client->call('im.chat.user.list', array( + 'chat_id' => (int) $chatId + )); + } +} \ No newline at end of file diff --git a/src/stub/bitrix24.php b/src/stub/bitrix24.php index 4c0a295d..2b99b576 100644 --- a/src/stub/bitrix24.php +++ b/src/stub/bitrix24.php @@ -2,7 +2,6 @@ namespace Bitrix24\Stub; use Bitrix24\Contracts\iBitrix24; -use Bitrix24\Stub\Logger; use Psr\Log\LoggerInterface; use Bitrix24\Bitrix24Exception; @@ -17,6 +16,7 @@ /** * Class Bitrix24 * fake Bitrix24 object, analog dev/null + * * @package Bitrix24\Stub */ class Bitrix24 implements iBitrix24 @@ -28,9 +28,12 @@ class Bitrix24 implements iBitrix24 /** * Create a object to work with Bitrix24 REST API service + * * @param bool $isSaveRawResponse - if true raw response from bitrix24 will be available from method getRawResponse, this is debug mode * @param null|LoggerInterface $obLogger - instance of \Monolog\Logger + * * @throws Bitrix24Exception + * * @return Bitrix24 */ public function __construct($isSaveRawResponse = false, LoggerInterface $obLogger = null) @@ -40,6 +43,7 @@ public function __construct($isSaveRawResponse = false, LoggerInterface $obLogge /** * Get a random string to sign protected api-call. Use salt for argument "state" in secure api-call * random string is a result of mt_rand function + * * @return int */ public function getSecuritySignSalt() @@ -48,15 +52,20 @@ public function getSecuritySignSalt() /** * Set member ID — portal GUID + * * @param string $memberId + * * @throws Bitrix24Exception + * * @return true; */ public function setMemberId($memberId) { } + /** * Get memeber ID + * * @return string | null */ public function getMemberId() @@ -65,8 +74,11 @@ public function getMemberId() /** * Set redirect URI + * * @param string $redirectUri + * * @throws Bitrix24Exception + * * @return true; */ public function setRedirectUri($redirectUri) @@ -75,6 +87,7 @@ public function setRedirectUri($redirectUri) /** * Get redirect URI + * * @return string | null */ public function getRedirectUri() @@ -83,9 +96,12 @@ public function getRedirectUri() /** * Set access token + * * @param string $accessToken + * * @throws Bitrix24Exception - * @return true; + * + * @return true */ public function setAccessToken($accessToken) { @@ -93,6 +109,7 @@ public function setAccessToken($accessToken) /** * Get access token + * * @return string | null */ public function getAccessToken() @@ -101,8 +118,11 @@ public function getAccessToken() /** * Set refresh token + * * @param $refreshToken + * * @throws Bitrix24Exception + * * @return true; */ public function setRefreshToken($refreshToken) @@ -111,6 +131,7 @@ public function setRefreshToken($refreshToken) /** * Get refresh token + * * @return string */ public function getRefreshToken() @@ -119,9 +140,12 @@ public function getRefreshToken() /** * Set domain + * * @param $domain + * * @throws Bitrix24Exception - * @return true; + * + * @return true */ public function setDomain($domain) { @@ -129,6 +153,7 @@ public function setDomain($domain) /** * Get domain + * * @return string | null */ public function getDomain() @@ -137,8 +162,11 @@ public function getDomain() /** * Set application scope + * * @param array $applicationScope + * * @return boolean + * * @throws Bitrix24Exception */ public function setApplicationScope(array $applicationScope) @@ -147,6 +175,8 @@ public function setApplicationScope(array $applicationScope) /** * Get application scope + * + * @return array */ public function getApplicationScope() { @@ -154,9 +184,12 @@ public function getApplicationScope() /** * Set application id + * * @param string $applicationId + * * @throws Bitrix24Exception - * @return true; + * + * @return true */ public function setApplicationId($applicationId) { @@ -164,6 +197,7 @@ public function setApplicationId($applicationId) /** * Get application id + * * @return string */ public function getApplicationId() @@ -172,8 +206,11 @@ public function getApplicationId() /** * Set application secret + * * @param string $applicationSecret + * * @throws Bitrix24Exception + * * @return true; */ public function setApplicationSecret($applicationSecret) @@ -182,6 +219,7 @@ public function setApplicationSecret($applicationSecret) /** * Get application secret + * * @return string */ public function getApplicationSecret() @@ -191,7 +229,9 @@ public function getApplicationSecret() /** * Set custom cURL options, overriding default ones * @link http://php.net/manual/en/function.curl-setopt.php + * * @param array $options - array(CURLOPT_XXX => value1, CURLOPT_XXX2 => value2,...) + * * @return bool */ public function setCustomCurlOptions($options) @@ -201,6 +241,7 @@ public function setCustomCurlOptions($options) /** * Return raw request, contain all cURL options array and API query. Data available after you try to call method call * numbers of array keys is const of cURL module. Example: CURLOPT_RETURNTRANSFER = 19913 + * * @return array | null */ public function getRawRequest() @@ -209,6 +250,7 @@ public function getRawRequest() /** * Return result from function curl_getinfo. Data available after you try to call method call + * * @return array | null */ public function getRequestInfo() @@ -217,6 +259,7 @@ public function getRequestInfo() /** * Return additional parameters of last api-call. Data available after you try to call method call + * * @return array | null */ public function getMethodParameters() @@ -225,8 +268,10 @@ public function getMethodParameters() /** * Execute Bitrix24 REST API method + * * @param string $methodName * @param array $additionalParameters + * * @throws Bitrix24Exception * @throws Bitrix24ApiException * @throws Bitrix24TokenIsInvalid @@ -234,6 +279,7 @@ public function getMethodParameters() * @throws Bitrix24WrongClientException * @throws Bitrix24MethodNotFoundException * @throws Bitrix24SecurityException + * * @return array */ public function call($methodName, array $additionalParameters = array()) @@ -243,7 +289,9 @@ public function call($methodName, array $additionalParameters = array()) /** * Get raw response from Bitrix24 before json_decode call, method available only in debug mode. * To activate debug mode you must before set to true flag isSaveRawResponse in class construct + * * @throws Bitrix24Exception + * * @return string */ public function getRawResponse() @@ -252,7 +300,9 @@ public function getRawResponse() /** * Get new access token + * * @return array + * * @throws Bitrix24Exception * @throws Bitrix24ApiException * @throws Bitrix24TokenIsInvalid @@ -266,8 +316,11 @@ public function getNewAccessToken() /** * Authorize and get first access token + * * @param $code + * * @return array + * * @throws Bitrix24ApiException * @throws Bitrix24Exception * @throws Bitrix24IoException @@ -283,12 +336,14 @@ public function getFirstAccessToken($code) /** * Check is access token expire, call list of all available api-methods from B24 portal with current access token * if we have an error code expired_token then return true else return false + * * @throws Bitrix24Exception * @throws Bitrix24ApiException * @throws Bitrix24TokenIsInvalid * @throws Bitrix24TokenIsExpired * @throws Bitrix24WrongClientException * @throws Bitrix24MethodNotFoundException + * * @return boolean */ public function isAccessTokenExpire() @@ -297,9 +352,12 @@ public function isAccessTokenExpire() /** * Get list of all methods available for current application + * * @param array | null $applicationScope * @param bool $isFull + * * @return array + * * @throws Bitrix24Exception */ public function getAvailableMethods(array $applicationScope = array(), $isFull = false) @@ -308,12 +366,55 @@ public function getAvailableMethods(array $applicationScope = array(), $isFull = /** * get list of scope for current application from bitrix24 api + * * @param bool $isFull + * * @throws Bitrix24Exception + * * @return array */ public function getScope($isFull=false) { } + + /** + * set CURL request count retries + * + * @param $retriesCnt + * + * @return boolean + */ + public function setRetriesToConnectCount($retriesCnt = 1) + { + } + + /** + * set retries to connect timeout in microseconds + * + * @param $microseconds + * + * @return boolean + */ + public function setRetriesToConnectTimeout($microseconds = 1000000) + { + } + + /** + * get CURL request count retries + * + * @return int + */ + public function getRetriesToConnectCount() + { + } + + /** + * get retries to connect timeout in microseconds + * + * @return mixed + */ + public function getRetriesToConnectTimeout() + { + } } diff --git a/src/stub/logger.php b/src/stub/logger.php deleted file mode 100644 index 34389a0f..00000000 --- a/src/stub/logger.php +++ /dev/null @@ -1,130 +0,0 @@ -setMemberId('valid_member_id'); $this->assertTrue($result); } @@ -54,7 +55,7 @@ public function testSetMemberIdWithValidArgument() public function testSetMemberIdWithNullArgument() { $this->setExpectedException('\Bitrix24\Bitrix24Exception'); - $obBitrix24 = new Bitrix24(false, new Bitrix24StubLogger()); + $obBitrix24 = new Bitrix24(false, new NullLogger()); $result = $obBitrix24->setMemberId(null); $this->assertTrue($result); } @@ -64,7 +65,7 @@ public function testSetMemberIdWithNullArgument() public function testSetMemberIdWithEmptyStringArgument() { $this->setExpectedException('\Bitrix24\Bitrix24Exception'); - $obBitrix24 = new Bitrix24(false, new Bitrix24StubLogger()); + $obBitrix24 = new Bitrix24(false, new NullLogger()); $result = $obBitrix24->setMemberId(''); $this->assertTrue($result); } @@ -74,7 +75,7 @@ public function testSetMemberIdWithEmptyStringArgument() public function testSetRetriesToConnectCountWithNull() { $this->setExpectedException('\Bitrix24\Bitrix24Exception'); - $obBitrix24 = new Bitrix24(false, new Bitrix24StubLogger()); + $obBitrix24 = new Bitrix24(false, new NullLogger()); $result = $obBitrix24->setRetriesToConnectCount(null); } /** @@ -82,7 +83,7 @@ public function testSetRetriesToConnectCountWithNull() */ public function testSetRetriesToConnectCountWithEmptyArgs() { - $obBitrix24 = new Bitrix24(false, new Bitrix24StubLogger()); + $obBitrix24 = new Bitrix24(false, new NullLogger()); $result = $obBitrix24->setRetriesToConnectCount(); $this->assertTrue($result); } @@ -91,7 +92,7 @@ public function testSetRetriesToConnectCountWithEmptyArgs() */ public function testSetRetriesToConnectCountWithValidArgs() { - $obBitrix24 = new Bitrix24(false, new Bitrix24StubLogger()); + $obBitrix24 = new Bitrix24(false, new NullLogger()); $result = $obBitrix24->setRetriesToConnectCount(1); $this->assertTrue($result); } @@ -101,7 +102,7 @@ public function testSetRetriesToConnectCountWithValidArgs() public function testSetRetriesToConnectTimeoutWithNull() { $this->setExpectedException('\Bitrix24\Bitrix24Exception'); - $obBitrix24 = new Bitrix24(false, new Bitrix24StubLogger()); + $obBitrix24 = new Bitrix24(false, new NullLogger()); $result = $obBitrix24->setRetriesToConnectTimeout(null); } /** @@ -109,7 +110,7 @@ public function testSetRetriesToConnectTimeoutWithNull() */ public function testSetRetriesToConnectTimeoutWithEmptyArgs() { - $obBitrix24 = new Bitrix24(false, new Bitrix24StubLogger()); + $obBitrix24 = new Bitrix24(false, new NullLogger()); $result = $obBitrix24->setRetriesToConnectTimeout(); $this->assertTrue($result); } @@ -118,7 +119,7 @@ public function testSetRetriesToConnectTimeoutWithEmptyArgs() */ public function testSetRetriesToConnectTimeoutWithValidArgs() { - $obBitrix24 = new Bitrix24(false, new Bitrix24StubLogger()); + $obBitrix24 = new Bitrix24(false, new NullLogger()); $result = $obBitrix24->setRetriesToConnectTimeout(1000000); $this->assertTrue($result); } diff --git a/tests/src/classes/im/chatTest.php b/tests/src/classes/im/chatTest.php new file mode 100644 index 00000000..c6f8f4cf --- /dev/null +++ b/tests/src/classes/im/chatTest.php @@ -0,0 +1,268 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24; + +use \Bitrix24\Im\Chat; +use \Bitrix24\Contracts\iBitrix24; +use \Bitrix24\Stub\Bitrix24 as Bitrix24NullObject; + +use \Psr\Log\NullLogger; + +/** + * Class ChatTest + * @package Bitrix24 + */ +class ChatTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var iBitrix24 + */ + protected $bitrix24App; + + /** + * @var int + */ + protected $defaultChatId; + + /** + * @return void + */ + protected function setUp() + { + $this->bitrix24App = new Bitrix24NullObject(); + $this->defaultChatId = 1; + } + + /** + * @covers \Bitrix24\Im\Chat::userList + */ + public function testUserListWithNullArgument() + { + $obChat = new Chat($this->bitrix24App); + $obChat->userList(null); + } + + /** + * @covers \Bitrix24\Im\Chat::userList + */ + public function testUserListWithNumericArgument() + { + $obChat = new Chat($this->bitrix24App); + $obChat->userList($this->defaultChatId); + } + + /** + * @covers \Bitrix24\Im\Chat::add + */ + public function testAddChatWithTitleAndDescription() + { + $obChat = new Chat($this->bitrix24App); + $obChat->add('chat title', 'chat description'); + } + + /** + * @covers \Bitrix24\Im\Chat::delete + */ + public function testDeleteWithNullArgument() + { + $obChat = new Chat($this->bitrix24App); + $obChat->delete(null); + } + + /** + * @covers \Bitrix24\Im\Chat::delete + */ + public function testDeleteWithNumericArgument() + { + $obChat = new Chat($this->bitrix24App); + $obChat->delete($this->defaultChatId); + } + + /** + * @covers \Bitrix24\Im\Chat::setOwner + */ + public function testSetOwnerWithNullChatId() + { + $obChat = new Chat($this->bitrix24App); + $obChat->setOwner(null, $this->defaultChatId); + } + + /** + * @covers \Bitrix24\Im\Chat::setOwner + */ + public function testSetOwnerWithNullUserId() + { + $obChat = new Chat($this->bitrix24App); + $obChat->setOwner($this->defaultChatId, null); + } + + /** + * @covers \Bitrix24\Im\Chat::setOwner + */ + public function testSetOwnerWithValidArguments() + { + $obChat = new Chat($this->bitrix24App); + $obChat->setOwner($this->defaultChatId, 1); + } + + /** + * @covers \Bitrix24\Im\Chat::updateColor + */ + public function testUpdateColorWithValidArguments() + { + $obChat = new Chat($this->bitrix24App); + $obChat->updateColor($this->defaultChatId, 'RED'); + } + + /** + * @covers \Bitrix24\Im\Chat::updateColor + */ + public function testUpdateColorWithNullChatId() + { + $obChat = new Chat($this->bitrix24App); + $obChat->updateColor(null, 'RED'); + } + + /** + * @covers \Bitrix24\Im\Chat::updateColor + */ + public function testUpdateColorWithNullColor() + { + $obChat = new Chat($this->bitrix24App); + $obChat->updateColor($this->defaultChatId, null); + } + + /** + * @covers \Bitrix24\Im\Chat::updateTitle + */ + public function testUpdateTitleWithValidArguments() + { + $obChat = new Chat($this->bitrix24App); + $obChat->updateTitle($this->defaultChatId, 'test title'); + } + + /** + * @covers \Bitrix24\Im\Chat::updateTitle + */ + public function testUpdateTitleWithNullChatId() + { + $obChat = new Chat($this->bitrix24App); + $obChat->updateTitle(null, 'test title'); + } + + /** + * @covers \Bitrix24\Im\Chat::updateTitle + */ + public function testUpdateTitleWithNullTitle() + { + $obChat = new Chat($this->bitrix24App); + $obChat->updateTitle($this->defaultChatId, null); + } + + /** + * @covers \Bitrix24\Im\Chat::updateAvatar + */ + public function testUpdateAvatarWithValidArguments() + { + $obChat = new Chat($this->bitrix24App); + $obChat->updateAvatar($this->defaultChatId, 'test avatar'); + } + + /** + * @covers \Bitrix24\Im\Chat::updateAvatar + */ + public function testUpdateAvatarWithNullChatId() + { + $obChat = new Chat($this->bitrix24App); + $obChat->updateAvatar(null, 'test avatar'); + } + + /** + * @covers \Bitrix24\Im\Chat::updateAvatar + */ + public function testUpdateAvatarWithNullAvatar() + { + $obChat = new Chat($this->bitrix24App); + $obChat->updateAvatar($this->defaultChatId, null); + } + + /** + * @covers \Bitrix24\Im\Chat::sendTyping + */ + public function testSendTypingWithValidArguments() + { + $obChat = new Chat($this->bitrix24App); + $obChat->sendTyping($this->defaultChatId); + } + + /** + * @covers \Bitrix24\Im\Chat::sendTyping + */ + public function testSendTypingWithNullChatId() + { + $obChat = new Chat($this->bitrix24App); + $obChat->sendTyping(null); + } + + /** + * @covers \Bitrix24\Im\Chat::userDelete + */ + public function testUserDeleteWithValidArguments() + { + $obChat = new Chat($this->bitrix24App); + $obChat->userDelete($this->defaultChatId, 1); + } + + /** + * @covers \Bitrix24\Im\Chat::userDelete + */ + public function testUserDeleteWithNullChatId() + { + $obChat = new Chat($this->bitrix24App); + $obChat->userDelete(null, 1); + } + + /** + * @covers \Bitrix24\Im\Chat::userDelete + */ + public function testUserDeleteWithNullUserId() + { + $obChat = new Chat($this->bitrix24App); + $obChat->userDelete($this->defaultChatId, null); + } + + /** + * @covers \Bitrix24\Im\Chat::userAdd + */ + public function testUserAddWithValidArguments() + { + $obChat = new Chat($this->bitrix24App); + $obChat->userAdd($this->defaultChatId, array(2, 3, 4)); + } + + /** + * @covers \Bitrix24\Im\Chat::userAdd + */ + public function testUserAddWithNullChatId() + { + $obChat = new Chat($this->bitrix24App); + $obChat->userAdd(null, array(2, 3, 4)); + } + + /** + * @covers \Bitrix24\Im\Chat::userAdd + */ + public function testUserAddWithEmptyArray() + { + $obChat = new Chat($this->bitrix24App); + $obChat->userAdd($this->defaultChatId, array()); + } +} \ No newline at end of file From 67446a068818ba3257618b333caa533f3c956f19 Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Wed, 27 Apr 2016 01:12:43 +0300 Subject: [PATCH 060/647] task#40: Add support for deleted portals --- CHANGELOG.md | 3 +++ src/bitrix24.php | 28 +++++++++++++++++++++++++++- src/bitrix24exception.php | 2 ++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5900baf..0ca84f8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,7 @@ # bitrix24-php-sdk change log +## 0.2.1 (27.04.2016) +* add exception class `Bitrix24PortalDeleted` and handle Bitrix24 portal deleted event. See issue [Add support for deleted portals #40](https://github.com/mesilov/bitrix24-php-sdk/issues/40) + ## 0.2.0 (24.06.2015) * add class Deal * add class LiveFeedMessage diff --git a/src/bitrix24.php b/src/bitrix24.php index 9584d773..111ce81f 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -508,7 +508,7 @@ protected function executeRequest($url, array $additionalParameters = array()) continue; } $this->requestInfo = curl_getinfo($curl); - $this->log->debug('cURL request info', array($this->requestInfo)); + $this->log->debug('cURL request info', array($this->getRequestInfo())); curl_close($curl); break; } @@ -516,6 +516,32 @@ protected function executeRequest($url, array $additionalParameters = array()) { $this->rawResponse = $curlResult; } + // handling URI level resource errors + switch ($this->requestInfo['http_code']) + { + case 403: + $errorMsg = sprintf('portal [%s] deleted, query aborted', $this->getDomain()); + $this->log->error($errorMsg, + array( + // portal specific settings + 'B24_DOMAIN' => $this->getDomain(), + 'B24_MEMBER_ID' => $this->getMemberId(), + 'B24_ACCESS_TOKEN' => $this->getAccessToken(), + 'B24_REFRESH_TOKEN' => $this->getRefreshToken(), + // application settings + 'APPLICATION_SCOPE' => $this->getApplicationScope(), + 'APPLICATION_ID' => $this->getApplicationId(), + 'APPLICATION_SECRET' => $this->getApplicationSecret(), + 'REDIRECT_URI' => $this->getRedirectUri(), + // network + 'RAW_REQUEST' => $this->getRawRequest(), + 'CURL_REQUEST_INFO' => $this->getRequestInfo(), + 'RAW_RESPONSE' => $curlResult + ) + ); + throw new Bitrix24PortalDeleted($errorMsg); + break; + } // handling json_decode errors $jsonResult = json_decode($curlResult, true); unset($curlResult); diff --git a/src/bitrix24exception.php b/src/bitrix24exception.php index 7b0fa41b..5c0b78a7 100644 --- a/src/bitrix24exception.php +++ b/src/bitrix24exception.php @@ -10,6 +10,7 @@ * \Bitrix24MethodNotFoundException — API-method not found * \Bitrix24TokenIsInvalid — The access token provided is invalid * \Bitrix24TokenIsExpired — The access token provided has expired + * \Bitrix24PortalDeleted — Bitrix24 portal deleted * \Bitrix24SecurityException — Security errors for protected methods */ namespace Bitrix24; @@ -20,4 +21,5 @@ class Bitrix24WrongClientException extends Bitrix24ApiException {} class Bitrix24MethodNotFoundException extends Bitrix24ApiException {} class Bitrix24TokenIsInvalid extends Bitrix24ApiException {} class Bitrix24TokenIsExpired extends Bitrix24ApiException {} +class Bitrix24PortalDeleted extends Bitrix24ApiException {} class Bitrix24SecurityException extends Bitrix24Exception {} From 68051598c0c6336bac618ec8d8c40fbfd56aa77e Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Wed, 4 May 2016 17:37:48 +0300 Subject: [PATCH 061/647] task#41: add full support for chats --- CHANGELOG.md | 83 +++++++++++-------- src/classes/im/attach/attach.php | 16 +++- src/classes/im/attach/iattach.php | 5 ++ src/classes/im/attach/item/message.php | 52 ++++++++++++ src/classes/im/chat.php | 2 +- src/presets/im/ichatcolor.php | 82 ++++++++++++++++++ tests/src/classes/im/attach/attachTest.php | 74 +++++++++++++++++ .../classes/im/attach/item/delimiterTest.php | 30 +++++++ tests/src/classes/im/attach/item/fileTest.php | 30 +++++++ tests/src/classes/im/attach/item/gridTest.php | 30 +++++++ .../src/classes/im/attach/item/imageTest.php | 30 +++++++ tests/src/classes/im/attach/item/linkTest.php | 30 +++++++ .../classes/im/attach/item/messageTest.php | 30 +++++++ tests/src/classes/im/attach/item/userTest.php | 30 +++++++ 14 files changed, 484 insertions(+), 40 deletions(-) create mode 100644 src/classes/im/attach/item/message.php create mode 100644 src/presets/im/ichatcolor.php create mode 100644 tests/src/classes/im/attach/attachTest.php create mode 100644 tests/src/classes/im/attach/item/delimiterTest.php create mode 100644 tests/src/classes/im/attach/item/fileTest.php create mode 100644 tests/src/classes/im/attach/item/gridTest.php create mode 100644 tests/src/classes/im/attach/item/imageTest.php create mode 100644 tests/src/classes/im/attach/item/linkTest.php create mode 100644 tests/src/classes/im/attach/item/messageTest.php create mode 100644 tests/src/classes/im/attach/item/userTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ca84f8b..401bc73d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,66 +1,79 @@ # bitrix24-php-sdk change log +## 0.3.0 (04.05.2016) +* add class `Bitrix24\Im\Attach\Item\Message` class implements work with string messages in attach item +* add interface `Bitrix24\Presets\Im\iChatColor` with chat color presets +* add phpUnit tests for items: + * `Bitrix24\Im\Attach\Item\Delimiter` + * `Bitrix24\Im\Attach\Item\File` + * `Bitrix24\Im\Attach\Item\Grid` + * `Bitrix24\Im\Attach\Item\Image` + * `Bitrix24\Im\Attach\Item\Link` + * `Bitrix24\Im\Attach\Item\Message` + * `Bitrix24\Im\Attach\Item\User` +* fixed bug in class `Bitrix24\Im\Attach\Attach` + ## 0.2.1 (27.04.2016) * add exception class `Bitrix24PortalDeleted` and handle Bitrix24 portal deleted event. See issue [Add support for deleted portals #40](https://github.com/mesilov/bitrix24-php-sdk/issues/40) ## 0.2.0 (24.06.2015) -* add class Deal -* add class LiveFeedMessage +* add class `Deal` +* add class `LiveFeedMessage` * add task fields presets -* add Bitrix24\CRM\Lead entity +* add `Bitrix24\CRM\Lead` entity * add some event fields in presets -* add Bitrix24\CRM\Contact entity -* add class Bitrix24\Task\ChecklistItem -* add class Bitrix24\Task\CommentItem -* add class Bitrix24\Task\ElapsedItem -* add class Bitrix24\Task\Item -* add class Bitrix24\Task\Items +* add `Bitrix24\CRM\Contact` entity +* add class `Bitrix24\Task\ChecklistItem` +* add class `Bitrix24\Task\CommentItem` +* add class `Bitrix24\Task\ElapsedItem` +* add class `Bitrix24\Task\Item` +* add class `Bitrix24\Task\Items` * changed PHP version for Composer -* fixed bug in Bitrix24\Presets\CRM\Lead -* fixed bug in class Invoice -* remove class Bitrix24\Task\TaskItems -* remove class Bitrix24\Task\TaskItem +* fixed bug in `Bitrix24\Presets\CRM\Lead` +* fixed bug in class `Invoice` +* remove class `Bitrix24\Task\TaskItems` +* remove class `Bitrix24\Task\TaskItem` ## 0.1.4 (18.04.2015) * add presets for user fields data type structure -* add method Update and predefined constants in class Invoice -* add protected method handleBitrix24APILevelErrors in a base class +* add method `Update` and predefined constants in class `Invoice` +* add protected method `handleBitrix24APILevelErrors` in a base class * add some presets for main entity -* add presets for entity Lead -* add method get in class Lead -* add class IM +* add presets for entity `Lead` +* add method get in class `Lead` +* add class `IM` * add methods get and delete for invoice entity -* add presets for class Contact +* add presets for class `Contact` * add entity events -* add class Invoice in namespace Bitrix24\CRM +* add class `Invoice` in namespace `Bitrix24\CRM` * fixed bug in Fix method isAccessTokenExpire ## 0.1.3 (24.08.2014) -* add const TOTAL and RESULT for class \Bitrix24\Presets\Main -* add class Bitrix24\Presets\Users\Fields for Bitrix24 users fields -* add class Bitrix24\Departments\Department -* add class Bitrix24\Presets\Events for Bitrix24 event codes -* add class Bitrix24\Presets\Uri for Bitrix24 uri constants -* add class Bitrix24\Presets\Scope for Bitrix24 scope constants -* add class Bitrix24\Application -* add class Lead -* add class Events -* add class Contacts +* add const `TOTAL` and `RESULT` for class `Bitrix24\Presets\Main` +* add class `Bitrix24\Presets\Users\Fields` for Bitrix24 users fields +* add class `Bitrix24\Departments\Department` +* add class `Bitrix24\Presets\Events` for Bitrix24 event codes +* add class `Bitrix24\Presets\Uri` for Bitrix24 uri constants +* add class `Bitrix24\Presets\Scope` for Bitrix24 scope constants +* add class `Bitrix24\Application` +* add class `Lead` +* add class `Events` +* add class `Contacts` * add a composer support * fixed bug in main class, remove require_once instructions -* fixed bug in __construct in abstract class Bitrix24Entity +* fixed bug in __construct in abstract class `Bitrix24Entity` ## 0.1.2 (22.01.2014) * add security sign support in api-call -* add class User +* add class `User` * add method «admin» — Check is current user admin -* add methods getRedirectUri and setRedirectUri, redirect uri arg support in method getNewAccessToken -* add a class TaskItem +* add methods `getRedirectUri` and `setRedirectUri`, redirect uri arg support in method `getNewAccessToken` +* add a class `TaskItem` * add MIT-LICENSE ## 0.1.1 (9.10.2013) * add namespace support * add classes of Bitrix24 parts: tasks, sonet -* add base class Bitrix24Entity +* add base class `Bitrix24Entity` ## 0.1.0 (26.10.2013) * Initial release \ No newline at end of file diff --git a/src/classes/im/attach/attach.php b/src/classes/im/attach/attach.php index fefc0b54..e53e00a1 100644 --- a/src/classes/im/attach/attach.php +++ b/src/classes/im/attach/attach.php @@ -22,7 +22,7 @@ class Attach implements iAttach /** * @var string */ - const CHAT = "CHAT"; + const CHAT = 'CHAT'; /** * @var int $id Unix timestamp */ @@ -49,9 +49,10 @@ public function __construct($id = null, $color = null) if (self::CHAT !== $color) { - if(null === $color) + $this->color = $color; + if(null === $this->color) { - $this->color = $this->setStatusNormal(); + $this->setStatusNormal(); } } } @@ -73,10 +74,17 @@ public function getData() 'ID' => $this->id, 'BLOCKS' => $this->getAttachList(), 'COLOR' => $this->color - ); } + /** + * @return array + */ + public function getAttachItems() + { + return $this->attachItems; + } + /** * @return array */ diff --git a/src/classes/im/attach/iattach.php b/src/classes/im/attach/iattach.php index 20464fd7..cb730078 100644 --- a/src/classes/im/attach/iattach.php +++ b/src/classes/im/attach/iattach.php @@ -41,4 +41,9 @@ public function setStatusAttention(); * @return mixed */ public function setStatusProblem(); + + /** + * @return array + */ + public function getAttachItems(); } diff --git a/src/classes/im/attach/item/message.php b/src/classes/im/attach/item/message.php new file mode 100644 index 00000000..dd3f0c38 --- /dev/null +++ b/src/classes/im/attach/item/message.php @@ -0,0 +1,52 @@ + and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Bitrix24\Im\Attach\Item; +use Bitrix24\Im\Attach\iAttachItem; + +/** + * Class Message + * @package Bitrix24\Im\Attach\Item + */ +class Message implements iAttachItem +{ + /** + * @var string + */ + const ATTACH_TYPE_CODE = 'MESSAGE'; + /** + * @var + */ + protected $message; + + /** + * Message constructor. + * @param $message + */ + public function __construct($message) + { + $this->message = $message; + } + + /** + * @return array + */ + public function getAttachData() + { + return $this->message; + } + + /** + * @return string + */ + public function getAttachTypeCode() + { + return self::ATTACH_TYPE_CODE; + } +} \ No newline at end of file diff --git a/src/classes/im/chat.php b/src/classes/im/chat.php index 3fb2195b..07ca311d 100644 --- a/src/classes/im/chat.php +++ b/src/classes/im/chat.php @@ -24,7 +24,7 @@ class Chat extends Bitrix24Entity * * @param string $title * @param string $description - * @param string $color + * @param string $color chat color in Bitrix24\Presets\Im\iChatColor for mobile * @param string $message * @param array $users * @param string $avatarImgInBase64 diff --git a/src/presets/im/ichatcolor.php b/src/presets/im/ichatcolor.php new file mode 100644 index 00000000..e62da5f6 --- /dev/null +++ b/src/presets/im/ichatcolor.php @@ -0,0 +1,82 @@ + and contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Bitrix24\Presets\Im; + +/** + * Interface iChatColor + * @package Bitrix24\Presets\Im + */ +interface iChatColor +{ + /** + * @var string chat color in mobile + */ + const RED = '#FF0000'; + /** + * @var string chat color in mobile + */ + const GREEN = '#008000'; + /** + * @var string chat color in mobile + */ + const MINT = '#98ff98'; + /** + * @var string chat color in mobile + */ + const LIGHT_BLUE = '#add8e6'; + /** + * @var string chat color in mobile + */ + const DARK_BLUE = '#00008b'; + /** + * @var string chat color in mobile + */ + const PURPLE = '#800080'; + /** + * @var string chat color in mobile + */ + const AQUA = '#00ffff'; + /** + * @var string chat color in mobile + */ + const PINK = '#ffc0cb'; + /** + * @var string chat color in mobile + */ + const LIME = '#bfff00'; + /** + * @var string chat color in mobile + */ + const BROWN = '#a52a2a'; + /** + * @var string chat color in mobile + */ + const AZURE = '#007fff'; + /** + * @var string chat color in mobile + */ + const KHAKI = '#c3b091'; + /** + * @var string chat color in mobile + */ + const SAND = '#c2b280'; + /** + * @var string chat color in mobile + */ + const MARENGO = '#4C5866'; + /** + * @var string chat color in mobile + */ + const GRAY = '#808080'; + /** + * @var string chat color in mobile + */ + const GRAPHITE = '#383428'; +} \ No newline at end of file diff --git a/tests/src/classes/im/attach/attachTest.php b/tests/src/classes/im/attach/attachTest.php new file mode 100644 index 00000000..8e947072 --- /dev/null +++ b/tests/src/classes/im/attach/attachTest.php @@ -0,0 +1,74 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24; + +use \Bitrix24\Im\Attach\Attach; +use \Psr\Log\NullLogger; + +/** + * Class AttachTest + * @package Bitrix24 + */ +class AttachTest extends \PHPUnit_Framework_TestCase +{ + /** + * @covers \Bitrix24\Im\Attach\Attach::__construct + */ + public function testAttachConstructWithNullArguments() + { + $obItem = new Attach(null, null); + } + + /** + * @covers \Bitrix24\Im\Attach\Attach::setStatusNormal + */ + public function testAttachSetStatusNormal() + { + $obItem = new Attach(null, null); + $obItem->setStatusNormal(); + } + + /** + * @covers \Bitrix24\Im\Attach\Attach::setStatusAttention + */ + public function testAttachSetStatusAttention() + { + $obItem = new Attach(null, null); + $obItem->setStatusAttention(); + } + + /** + * @covers \Bitrix24\Im\Attach\Attach::setStatusProblem + */ + public function testAttachSetStatusProblem() + { + $obItem = new Attach(null, null); + $obItem->setStatusProblem(); + } + + /** + * @covers \Bitrix24\Im\Attach\Attach::getData + */ + public function testAttachGetData() + { + $obItem = new Attach(null, null); + $obItem->getData(); + } + + /** + * @covers \Bitrix24\Im\Attach\Attach::getAttachItems + */ + public function testAttachGetAttachItems() + { + $obItem = new Attach(null, null); + $obItem->getAttachItems(); + } +} \ No newline at end of file diff --git a/tests/src/classes/im/attach/item/delimiterTest.php b/tests/src/classes/im/attach/item/delimiterTest.php new file mode 100644 index 00000000..50ab0e10 --- /dev/null +++ b/tests/src/classes/im/attach/item/delimiterTest.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24; + +use \Bitrix24\Im\Attach\Item\Delimiter; +use \Psr\Log\NullLogger; + +/** + * Class DelimiterTest + * @package Bitrix24 + */ +class DelimiterTest extends \PHPUnit_Framework_TestCase +{ + /** + * @covers \Bitrix24\Im\Attach\Item\Delimiter::getAttachTypeCode + */ + public function testDelimiterTypeCode() + { + $obItem = new Delimiter(); + $this->assertSame($obItem->getAttachTypeCode(), 'DELIMITER'); + } +} \ No newline at end of file diff --git a/tests/src/classes/im/attach/item/fileTest.php b/tests/src/classes/im/attach/item/fileTest.php new file mode 100644 index 00000000..ae443591 --- /dev/null +++ b/tests/src/classes/im/attach/item/fileTest.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24; + +use \Bitrix24\Im\Attach\Item\File; +use \Psr\Log\NullLogger; + +/** + * Class FileTest + * @package Bitrix24 + */ +class FileTest extends \PHPUnit_Framework_TestCase +{ + /** + * @covers \Bitrix24\Im\Attach\Item\File::getAttachTypeCode + */ + public function testFileTypeCode() + { + $obItem = new File(null, null, null); + $this->assertSame($obItem->getAttachTypeCode(), 'FILE'); + } +} \ No newline at end of file diff --git a/tests/src/classes/im/attach/item/gridTest.php b/tests/src/classes/im/attach/item/gridTest.php new file mode 100644 index 00000000..8d073740 --- /dev/null +++ b/tests/src/classes/im/attach/item/gridTest.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24; + +use \Bitrix24\Im\Attach\Item\Grid; +use \Psr\Log\NullLogger; + +/** + * Class GridTest + * @package Bitrix24 + */ +class GridTest extends \PHPUnit_Framework_TestCase +{ + /** + * @covers \Bitrix24\Im\Attach\Item\Grid::getAttachTypeCode + */ + public function testGridTypeCode() + { + $obItem = new Grid(); + $this->assertSame($obItem->getAttachTypeCode(), 'GRID'); + } +} \ No newline at end of file diff --git a/tests/src/classes/im/attach/item/imageTest.php b/tests/src/classes/im/attach/item/imageTest.php new file mode 100644 index 00000000..94174095 --- /dev/null +++ b/tests/src/classes/im/attach/item/imageTest.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24; + +use \Bitrix24\Im\Attach\Item\Image; +use \Psr\Log\NullLogger; + +/** + * Class ImageTest + * @package Bitrix24 + */ +class ImageTest extends \PHPUnit_Framework_TestCase +{ + /** + * @covers \Bitrix24\Im\Attach\Item\Image::getAttachTypeCode + */ + public function testImageTypeCode() + { + $obItem = new Image(null, null); + $this->assertSame($obItem->getAttachTypeCode(), 'IMAGE'); + } +} \ No newline at end of file diff --git a/tests/src/classes/im/attach/item/linkTest.php b/tests/src/classes/im/attach/item/linkTest.php new file mode 100644 index 00000000..8b021815 --- /dev/null +++ b/tests/src/classes/im/attach/item/linkTest.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24; + +use \Bitrix24\Im\Attach\Item\Link; +use \Psr\Log\NullLogger; + +/** + * Class LinkTest + * @package Bitrix24 + */ +class LinkTest extends \PHPUnit_Framework_TestCase +{ + /** + * @covers \Bitrix24\Im\Attach\Item\Link::getAttachTypeCode + */ + public function testLinkTypeCode() + { + $obItem = new Link(null, null, null, null); + $this->assertSame($obItem->getAttachTypeCode(), 'LINK'); + } +} \ No newline at end of file diff --git a/tests/src/classes/im/attach/item/messageTest.php b/tests/src/classes/im/attach/item/messageTest.php new file mode 100644 index 00000000..1693eefd --- /dev/null +++ b/tests/src/classes/im/attach/item/messageTest.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24; + +use \Bitrix24\Im\Attach\Item\Message; +use \Psr\Log\NullLogger; + +/** + * Class MessageTest + * @package Bitrix24 + */ +class MessageTest extends \PHPUnit_Framework_TestCase +{ + /** + * @covers \Bitrix24\Im\Attach\Item\Message::getAttachTypeCode + */ + public function testUserListWithNullArgument() + { + $obItem = new Message('Test message'); + $this->assertSame($obItem->getAttachTypeCode(), 'MESSAGE'); + } +} \ No newline at end of file diff --git a/tests/src/classes/im/attach/item/userTest.php b/tests/src/classes/im/attach/item/userTest.php new file mode 100644 index 00000000..72999dc6 --- /dev/null +++ b/tests/src/classes/im/attach/item/userTest.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24; + +use \Bitrix24\Im\Attach\Item\User; +use \Psr\Log\NullLogger; + +/** + * Class UserTest + * @package Bitrix24 + */ +class UserTest extends \PHPUnit_Framework_TestCase +{ + /** + * @covers \Bitrix24\Im\Attach\Item\User::getAttachTypeCode + */ + public function testUserTypeCode() + { + $obItem = new User(null); + $this->assertSame($obItem->getAttachTypeCode(), 'USER'); + } +} \ No newline at end of file From 9d7db2ffe6e15f74ea6dc06feeb7357a03eb3613 Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Wed, 4 May 2016 18:24:42 +0300 Subject: [PATCH 062/647] task#41: fixed bug in method Attach::getAttachItems() --- CHANGELOG.md | 4 ++++ src/classes/im/attach/attach.php | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 401bc73d..af4408b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,8 @@ # bitrix24-php-sdk change log +## 0.3.1 (04.05.2016) +* add `dev` branch in GitHub repo +* fixed bug in class `Bitrix24\Im\Attach\Attach`, method `Attach::getAttachItems()` already return array + ## 0.3.0 (04.05.2016) * add class `Bitrix24\Im\Attach\Item\Message` class implements work with string messages in attach item * add interface `Bitrix24\Presets\Im\iChatColor` with chat color presets diff --git a/src/classes/im/attach/attach.php b/src/classes/im/attach/attach.php index e53e00a1..9cfa3d44 100644 --- a/src/classes/im/attach/attach.php +++ b/src/classes/im/attach/attach.php @@ -42,6 +42,8 @@ class Attach implements iAttach */ public function __construct($id = null, $color = null) { + $this->attachItems = array(); + if(null === $id) { $this->id = time(); @@ -94,7 +96,7 @@ private function getAttachList() /** * @var $obAttachItem iAttachItem */ - foreach($this->attachItems as $cnt => $obAttachItem) + foreach($this->getAttachItems() as $cnt => $obAttachItem) { $arResult[][$obAttachItem->getAttachTypeCode()] = $obAttachItem->getAttachData(); } From 48c8c132854e1216cdaea4267a02b012ea32cc50 Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Sat, 7 May 2016 15:10:23 +0300 Subject: [PATCH 063/647] task#42: fix error for empty attach items --- src/classes/im/notify.php | 316 ++++++++++++++++++-------------------- 1 file changed, 149 insertions(+), 167 deletions(-) diff --git a/src/classes/im/notify.php b/src/classes/im/notify.php index ca5273ea..ed70da03 100644 --- a/src/classes/im/notify.php +++ b/src/classes/im/notify.php @@ -8,6 +8,7 @@ * file that was distributed with this source code. */ namespace Bitrix24\Im; + use Bitrix24\Bitrix24Entity; use Bitrix24\Bitrix24Exception; use Bitrix24\Presets\Im\Fields as B24ImFields; @@ -19,175 +20,156 @@ */ class Notify extends Bitrix24Entity { - /** - * @param $userId - * @param $message - * @param string $tag - * @param string $subTag - * @param Attach|null $attachObject - * @return array - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function addPersonal($userId, $message, $tag = '', $subTag = '', Attach $attachObject = null) - { - if(null === $userId) - { - throw new Bitrix24Exception('user id is null'); - } - elseif(null === $message) - { - throw new Bitrix24Exception('message is null'); - } - elseif(null === $attachObject) - { - $attachObject = new Attach(); - } - $fullResult = $this->client->call( - 'im.notify.personal.add', - array( - 'user_id' => (int) $userId, - 'message' => (string) $message, - 'tag' => (string) $tag, - 'sub_tag' => (string) $subTag, - 'attach' => $attachObject->getData() - ) - ); - return $fullResult; - } + /** + * @param $userId + * @param $message + * @param string $tag + * @param string $subTag + * @param Attach|null $attachObject + * @return array + * @throws Bitrix24Exception + * @throws \Bitrix24\Bitrix24SecurityException + * @throws \Bitrix24\Bitrix24Exception + * @throws \Bitrix24\Bitrix24ApiException + * @throws \Bitrix24\Bitrix24TokenIsInvalid + * @throws \Bitrix24\Bitrix24TokenIsExpired + * @throws \Bitrix24\Bitrix24WrongClientException + * @throws \Bitrix24\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Bitrix24SecurityException + */ + public function addPersonal($userId, $message, $tag = '', $subTag = '', Attach $attachObject = null) + { + $arArgs = array( + 'user_id' => (int)$userId, + 'message' => (string)$message, + 'tag' => (string)$tag, + 'sub_tag' => (string)$subTag + ); + + if (null === $userId) { + throw new Bitrix24Exception('user id is null'); + } elseif (null === $message) { + throw new Bitrix24Exception('message is null'); + } elseif (null !== $attachObject) { + $arArgs['attach'] = $attachObject->getData(); + } + return $this->client->call('im.notify.personal.add', $arArgs); + } + + /** + * @param $userId + * @param $message + * @param string $tag + * @param string $subTag + * @param Attach|null $attachObject + * @return array + * @throws Bitrix24Exception + * @throws \Bitrix24\Bitrix24SecurityException + * @throws \Bitrix24\Bitrix24Exception + * @throws \Bitrix24\Bitrix24ApiException + * @throws \Bitrix24\Bitrix24TokenIsInvalid + * @throws \Bitrix24\Bitrix24TokenIsExpired + * @throws \Bitrix24\Bitrix24WrongClientException + * @throws \Bitrix24\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Bitrix24SecurityException + */ + public function addSystem($userId, $message, $tag = '', $subTag = '', Attach $attachObject = null) + { + $arArgs = array( + 'user_id' => (int)$userId, + 'message' => (string)$message, + 'tag' => (string)$tag, + 'sub_tag' => (string)$subTag + ); - /** - * @param $userId - * @param $message - * @param string $tag - * @param string $subTag - * @param Attach|null $attachObject - * @return array - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function addSystem($userId, $message, $tag = '', $subTag = '', Attach $attachObject = null) - { - if(null === $userId) - { - throw new Bitrix24Exception('user id is null'); - } - elseif(null === $message) - { - throw new Bitrix24Exception('message is null'); - } - elseif(null === $attachObject) - { - $attachObject = new Attach(); - } - $fullResult = $this->client->call( - 'im.notify.system.add', - array( - 'user_id' => (int) $userId, - 'message' => (string) $message, - 'tag' => (string) $tag, - 'sub_tag' => (string) $subTag, - 'attach' => $attachObject->getData() - ) - ); - return $fullResult; - } + if (null === $userId) { + throw new Bitrix24Exception('user id is null'); + } elseif (null === $message) { + throw new Bitrix24Exception('message is null'); + } elseif (null !== $attachObject) { + $arArgs['attach'] = $attachObject->getData(); + } + return $this->client->call('im.notify.system.add', $arArgs); + } - /** - * @param $id - * @return array - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function deleteById($id) - { - if(null === $id) - { - throw new Bitrix24Exception('id is null'); - } - $fullResult = $this->client->call( - 'im.notify.delete', - array( - 'id' => (int) $id - ) - ); - return $fullResult; - } + /** + * @param $id + * @return array + * @throws Bitrix24Exception + * @throws \Bitrix24\Bitrix24SecurityException + * @throws \Bitrix24\Bitrix24Exception + * @throws \Bitrix24\Bitrix24ApiException + * @throws \Bitrix24\Bitrix24TokenIsInvalid + * @throws \Bitrix24\Bitrix24TokenIsExpired + * @throws \Bitrix24\Bitrix24WrongClientException + * @throws \Bitrix24\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Bitrix24SecurityException + */ + public function deleteById($id) + { + if (null === $id) { + throw new Bitrix24Exception('id is null'); + } + $fullResult = $this->client->call( + 'im.notify.delete', + array( + 'id' => (int)$id + ) + ); + return $fullResult; + } - /** - * @param $tag - * @return array - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function deleteByTag($tag) - { - if(null === $tag) - { - throw new Bitrix24Exception('tag is null'); - } - $fullResult = $this->client->call( - 'im.notify.delete', - array( - 'tag' => (string) $tag - ) - ); - return $fullResult; - } + /** + * @param $tag + * @return array + * @throws Bitrix24Exception + * @throws \Bitrix24\Bitrix24SecurityException + * @throws \Bitrix24\Bitrix24Exception + * @throws \Bitrix24\Bitrix24ApiException + * @throws \Bitrix24\Bitrix24TokenIsInvalid + * @throws \Bitrix24\Bitrix24TokenIsExpired + * @throws \Bitrix24\Bitrix24WrongClientException + * @throws \Bitrix24\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Bitrix24SecurityException + */ + public function deleteByTag($tag) + { + if (null === $tag) { + throw new Bitrix24Exception('tag is null'); + } + $fullResult = $this->client->call( + 'im.notify.delete', + array( + 'tag' => (string)$tag + ) + ); + return $fullResult; + } - /** - * @param $subTag - * @return array - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function deleteBySubTag($subTag) - { - if(null === $subTag) - { - throw new Bitrix24Exception('subTag is null'); - } - $fullResult = $this->client->call( - 'im.notify.delete', - array( - 'sub_tag' => (string) $subTag - ) - ); - return $fullResult; - } + /** + * @param $subTag + * @return array + * @throws Bitrix24Exception + * @throws \Bitrix24\Bitrix24SecurityException + * @throws \Bitrix24\Bitrix24Exception + * @throws \Bitrix24\Bitrix24ApiException + * @throws \Bitrix24\Bitrix24TokenIsInvalid + * @throws \Bitrix24\Bitrix24TokenIsExpired + * @throws \Bitrix24\Bitrix24WrongClientException + * @throws \Bitrix24\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Bitrix24SecurityException + */ + public function deleteBySubTag($subTag) + { + if (null === $subTag) { + throw new Bitrix24Exception('subTag is null'); + } + $fullResult = $this->client->call( + 'im.notify.delete', + array( + 'sub_tag' => (string)$subTag + ) + ); + return $fullResult; + } } \ No newline at end of file From 3e58f4cf93d61803e9231cb8b795f24f6d75bd78 Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Sat, 7 May 2016 15:17:19 +0300 Subject: [PATCH 064/647] task#42: fix error for empty attach items, add CHANGELOG --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index af4408b2..40817e02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,7 @@ # bitrix24-php-sdk change log +## 0.3.2 (07.05.2016) +* fixed bug in class `Bitrix24\Im\Notify` see issue [ATTACH_ERROR for calls method im.notify for empty attach #42](https://github.com/mesilov/bitrix24-php-sdk/issues/42) + ## 0.3.1 (04.05.2016) * add `dev` branch in GitHub repo * fixed bug in class `Bitrix24\Im\Attach\Attach`, method `Attach::getAttachItems()` already return array From 496bad6f363f9832fa4e7ad39310618bcedc9229 Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Sun, 29 May 2016 22:01:42 +0300 Subject: [PATCH 065/647] task#43: Fix errors after change REST API to support self hosted version --- CHANGELOG.md | 3 +++ src/bitrix24.php | 52 +++++++++++++++++++++++++++--------------------- 2 files changed, 32 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 40817e02..3e2f8be5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,7 @@ # bitrix24-php-sdk change log +## 0.3.3 (28.05.2016) +* fixed bug in class `Bitrix24` see issue [Fix errors after change REST API to support self hosted version #43](https://github.com/mesilov/bitrix24-php-sdk/issues/43) + ## 0.3.2 (07.05.2016) * fixed bug in class `Bitrix24\Im\Notify` see issue [ATTACH_ERROR for calls method im.notify for empty attach #42](https://github.com/mesilov/bitrix24-php-sdk/issues/42) diff --git a/src/bitrix24.php b/src/bitrix24.php index 111ce81f..4c8c5bfe 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -17,6 +17,11 @@ class Bitrix24 implements iBitrix24 * @var string SDK version */ const VERSION = '1.0'; + + /** + * @var string OAuth server + */ + const OAUTH_SERVER = 'oauth.bitrix.info'; /** * @var string access token @@ -575,6 +580,11 @@ protected function executeRequest($url, array $additionalParameters = array()) */ public function call($methodName, array $additionalParameters = array()) { + $arAuthServerMethods = array( + 'app.info', + 'app.stat' + ); + if(null === $this->getDomain()) { throw new Bitrix24Exception('domain not found, you must call setDomain method before'); @@ -587,7 +597,15 @@ public function call($methodName, array $additionalParameters = array()) { throw new Bitrix24Exception('method name not found, you must set method name'); } - $url = 'https://'.$this->domain.'/rest/'.$methodName; + + if(in_array(strtolower($methodName), $arAuthServerMethods, true)) + { + $url = 'https://'.self::OAUTH_SERVER.'/rest/'.$methodName; + } + else + { + $url = 'https://'.$this->domain.'/rest/'.$methodName; + } $additionalParameters['auth'] = $this->accessToken; // save method parameters for debug $this->methodParameters = $additionalParameters; @@ -751,18 +769,13 @@ public function getRawResponse() */ public function getNewAccessToken() { - $domain = $this->getDomain(); $applicationId = $this->getApplicationId(); $applicationSecret = $this->getApplicationSecret(); $refreshToken = $this->getRefreshToken(); $applicationScope = $this->getApplicationScope(); $redirectUri = $this->getRedirectUri(); - if(null === $domain) - { - throw new Bitrix24Exception('domain not found, you must call setDomain method before'); - } - elseif(null === $applicationId) + if(null === $applicationId) { throw new Bitrix24Exception('application id not found, you must call setApplicationId method before'); } @@ -783,12 +796,12 @@ public function getNewAccessToken() throw new Bitrix24Exception('application redirect URI not found, you must call setRedirectUri method before'); } - $url = 'https://'.$domain.'/oauth/token/'. +// $url = 'https://'.self::OAUTH_SERVER.'/oauth/token/'. + $url = 'https://'.$this->getDomain().'/oauth/token/'. '?client_id='.urlencode($applicationId). '&grant_type=refresh_token'. '&client_secret='.$applicationSecret. '&refresh_token='.$refreshToken. - '&scope='.implode(',', array_map('urlencode', array_unique($applicationScope))). '&redirect_uri='.urlencode($redirectUri); $requestResult = $this->executeRequest($url); // handling bitrix24 api-level errors @@ -813,18 +826,12 @@ public function getNewAccessToken() */ public function getFirstAccessToken($code) { - $domain = $this->getDomain(); $applicationId = $this->getApplicationId(); $applicationSecret = $this->getApplicationSecret(); - //$refreshToken = $this->getRefreshToken(); $applicationScope = $this->getApplicationScope(); $redirectUri = $this->getRedirectUri(); - if(null === $domain) - { - throw new Bitrix24Exception('domain not found, you must call setDomain method before'); - } - elseif(null === $applicationId) + if(null === $applicationId) { throw new Bitrix24Exception('application id not found, you must call setApplicationId method before'); } @@ -841,11 +848,11 @@ public function getFirstAccessToken($code) throw new Bitrix24Exception('application redirect URI not found, you must call setRedirectUri method before'); } - $url = 'https://'.$domain.'/oauth/token/'. +// $url = 'https://'.self::OAUTH_SERVER.'/oauth/token/'. + $url = 'https://'.$this->getDomain().'/oauth/token/'. '?client_id='.urlencode($applicationId). '&grant_type=authorization_code'. '&client_secret='.$applicationSecret. - '&scope='.implode(',', array_map('urlencode', array_unique($applicationScope))). '&redirect_uri='.urlencode($redirectUri). '&code='.urlencode($code); @@ -882,9 +889,10 @@ public function isAccessTokenExpire() { throw new Bitrix24Exception('application id not found, you must call setAccessToken method before'); } +// $url = 'https://'.self::OAUTH_SERVER.'/rest/app.info?auth='.$accessToken; $url = 'https://'.$domain.'/rest/app.info?auth='.$accessToken; $requestResult = $this->executeRequest($url); - if(isset($requestResult['error']) && ('expired_token' === $requestResult['error'])) + if(in_array($requestResult['error'], array('expired_token', 'invalid_token', 'WRONG_TOKEN'), false)) { $isTokenExpire = true; } @@ -935,8 +943,7 @@ public function getAvailableMethods(array $applicationScope = array(), $isFull = $scope = '&scope='.implode(',', array_map('urlencode', array_unique($applicationScope))); } $url = 'https://'.$domain.'/rest/methods.json?auth='.$accessToken.$showAll.$scope; - $requestResult = $this->executeRequest($url); - return $requestResult; + return $this->executeRequest($url); } /** @@ -967,8 +974,7 @@ public function getScope($isFull=false) $showAll = '&full=true'; } $url = 'https://'.$domain.'/rest/scope.json?auth='.$accessToken.$showAll; - $requestResult = $this->executeRequest($url); - return $requestResult; + return $this->executeRequest($url); } /** From 027319b1c38b3c72513b684bf6c39bfbb7e8ea87 Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Mon, 6 Jun 2016 00:07:24 +0300 Subject: [PATCH 066/647] task#43: Fix errors after change REST API to support self hosted version, some bugfix --- CHANGELOG.md | 5 ++ src/bitrix24.php | 141 +++++++++++++++++++++----------------- src/bitrix24exception.php | 4 +- 3 files changed, 87 insertions(+), 63 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e2f8be5..3fdcde94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,9 @@ # bitrix24-php-sdk change log +## 0.3.4 (06.06.2016) +* add exception class `Bitrix24EmptyResponseException` +* in class `Bitrix24` add debug information for some error types +* temporary remove calls to oauth.bitrix.info for methods `app.info` and `app.stat` see issue [Fix errors after change REST API to support self hosted version #43](https://github.com/mesilov/bitrix24-php-sdk/issues/43) + ## 0.3.3 (28.05.2016) * fixed bug in class `Bitrix24` see issue [Fix errors after change REST API to support self hosted version #43](https://github.com/mesilov/bitrix24-php-sdk/issues/43) diff --git a/src/bitrix24.php b/src/bitrix24.php index 4c8c5bfe..753a5179 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -446,6 +446,31 @@ public function getMethodParameters() return $this->methodParameters; } + /** + * get error context + * + * @return array + */ + protected function getErrorContext() + { + return array( + // portal specific settings + 'B24_DOMAIN' => $this->getDomain(), + 'B24_MEMBER_ID' => $this->getMemberId(), + 'B24_ACCESS_TOKEN' => $this->getAccessToken(), + 'B24_REFRESH_TOKEN' => $this->getRefreshToken(), + // application settings + 'APPLICATION_SCOPE' => $this->getApplicationScope(), + 'APPLICATION_ID' => $this->getApplicationId(), + 'APPLICATION_SECRET' => $this->getApplicationSecret(), + 'REDIRECT_URI' => $this->getRedirectUri(), + // network + 'RAW_REQUEST' => $this->getRawRequest(), + 'CURL_REQUEST_INFO' => $this->getRequestInfo(), + 'RAW_RESPONSE' => $this->getRawResponse() + ); + } + /** * Execute a request API to Bitrix24 using cURL * @@ -453,6 +478,9 @@ public function getMethodParameters() * @param array $additionalParameters * * @throws Bitrix24Exception + * @throws Bitrix24PortalDeleted + * @throws Bitrix24IoException + * @throws Bitrix24EmptyResponseException * * @return array */ @@ -465,7 +493,7 @@ protected function executeRequest($url, array $additionalParameters = array()) CURLE_READ_ERROR, CURLE_OPERATION_TIMEOUTED, CURLE_HTTP_POST_ERROR, - CURLE_SSL_CONNECT_ERROR, + CURLE_SSL_CONNECT_ERROR ); $curlOptions = array( @@ -501,52 +529,42 @@ protected function executeRequest($url, array $additionalParameters = array()) $curlErrorNumber = curl_errno($curl); $errorMsg = sprintf('in try[%s] cURL error (code %s): %s'.PHP_EOL, $retriesCnt, $curlErrorNumber, curl_error($curl)); if (false === in_array($curlErrorNumber, $retryableErrorCodes, true) || !$retriesCnt) { - $this->log->error($errorMsg); + $this->log->error($errorMsg, $this->getErrorContext()); curl_close($curl); throw new Bitrix24IoException($errorMsg); } else { - $this->log->warning($errorMsg); + $this->log->warning($errorMsg, $this->getErrorContext()); } usleep($this->getRetriesToConnectTimeout()); continue; } $this->requestInfo = curl_getinfo($curl); + $this->rawResponse = $curlResult; $this->log->debug('cURL request info', array($this->getRequestInfo())); curl_close($curl); break; } - if(true === $this->isSaveRawResponse) - { - $this->rawResponse = $curlResult; - } + // handling URI level resource errors switch ($this->requestInfo['http_code']) { case 403: $errorMsg = sprintf('portal [%s] deleted, query aborted', $this->getDomain()); - $this->log->error($errorMsg, - array( - // portal specific settings - 'B24_DOMAIN' => $this->getDomain(), - 'B24_MEMBER_ID' => $this->getMemberId(), - 'B24_ACCESS_TOKEN' => $this->getAccessToken(), - 'B24_REFRESH_TOKEN' => $this->getRefreshToken(), - // application settings - 'APPLICATION_SCOPE' => $this->getApplicationScope(), - 'APPLICATION_ID' => $this->getApplicationId(), - 'APPLICATION_SECRET' => $this->getApplicationSecret(), - 'REDIRECT_URI' => $this->getRedirectUri(), - // network - 'RAW_REQUEST' => $this->getRawRequest(), - 'CURL_REQUEST_INFO' => $this->getRequestInfo(), - 'RAW_RESPONSE' => $curlResult - ) - ); + $this->log->error($errorMsg, $this->getErrorContext()); throw new Bitrix24PortalDeleted($errorMsg); break; } + + // handling server-side API errors: empty response from bitrix24 portal + if($curlResult === '') + { + $errorMsg = sprintf('empty response from portal [%s]', $this->getDomain()); + $this->log->error($errorMsg, $this->getErrorContext()); + throw new Bitrix24EmptyResponseException($errorMsg); + } + // handling json_decode errors $jsonResult = json_decode($curlResult, true); unset($curlResult); @@ -557,6 +575,7 @@ protected function executeRequest($url, array $additionalParameters = array()) * @todo add function json_last_error_msg() */ $errorMsg = 'fatal error in function json_decode.'.PHP_EOL.'Error code: '.$jsonErrorCode.PHP_EOL; + $this->log->error($errorMsg, $this->getErrorContext()); throw new Bitrix24Exception($errorMsg); } return $jsonResult; @@ -575,15 +594,18 @@ protected function executeRequest($url, array $additionalParameters = array()) * @throws Bitrix24WrongClientException * @throws Bitrix24MethodNotFoundException * @throws Bitrix24SecurityException + * @throws Bitrix24PortalDeleted + * @throws Bitrix24IoException + * @throws Bitrix24EmptyResponseException * * @return array */ public function call($methodName, array $additionalParameters = array()) { - $arAuthServerMethods = array( - 'app.info', - 'app.stat' - ); +// $arAuthServerMethods = array( +// 'app.info', +// 'app.stat' +// ); if(null === $this->getDomain()) { @@ -598,14 +620,14 @@ public function call($methodName, array $additionalParameters = array()) throw new Bitrix24Exception('method name not found, you must set method name'); } - if(in_array(strtolower($methodName), $arAuthServerMethods, true)) - { - $url = 'https://'.self::OAUTH_SERVER.'/rest/'.$methodName; - } - else - { +// if(in_array(strtolower($methodName), $arAuthServerMethods, true)) +// { +// $url = 'https://'.self::OAUTH_SERVER.'/rest/'.$methodName; +// } +// else +// { $url = 'https://'.$this->domain.'/rest/'.$methodName; - } +// } $additionalParameters['auth'] = $this->accessToken; // save method parameters for debug $this->methodParameters = $additionalParameters; @@ -701,25 +723,7 @@ protected function handleBitrix24APILevelErrors($arRequestResult, $methodName, a (array_key_exists('error_description', $arRequestResult) ? $arRequestResult['error_description'] : ''), $methodName, $this->getDomain()); - $this->log->error($errorMsg, array( - // response - 'REQUEST_RESULT' => $arRequestResult, - // query - 'METHOD_NAME' => $methodName, - 'ADDITIONAL_PARAMETERS' => $additionalParameters, - // portal specific settings - 'B24_DOMAIN' => $this->getDomain(), - 'B24_MEMBER_ID' => $this->getMemberId(), - 'B24_ACCESS_TOKEN' => $this->getAccessToken(), - 'B24_REFRESH_TOKEN' => $this->getRefreshToken(), - // application settings - 'APPLICATION_SCOPE' => $this->getApplicationScope(), - 'APPLICATION_ID' => $this->getApplicationId(), - 'APPLICATION_SECRET' => $this->getApplicationSecret(), - 'REDIRECT_URI' => $this->getRedirectUri(), - // network - 'RAW_REQUEST' => $this->getRawRequest(), - 'CURL_REQUEST_INFO' => $this->getRequestInfo())); + $this->log->error($errorMsg, $this->getErrorContext()); // throw specific API-level exceptions switch(strtoupper(trim($arRequestResult['error']))) { @@ -742,16 +746,10 @@ protected function handleBitrix24APILevelErrors($arRequestResult, $methodName, a * Get raw response from Bitrix24 before json_decode call, method available only in debug mode. * To activate debug mode you must before set to true flag isSaveRawResponse in class construct * - * @throws Bitrix24Exception - * - * @return string + * @return string | null */ public function getRawResponse() { - if(false === $this->isSaveRawResponse) - { - throw new Bitrix24Exception('you must before set to true flag isSaveRawResponse in class construct'); - } return $this->rawResponse; } @@ -766,6 +764,10 @@ public function getRawResponse() * @throws Bitrix24TokenIsExpired * @throws Bitrix24WrongClientException * @throws Bitrix24MethodNotFoundException + * @throws Bitrix24PortalDeleted + * @throws Bitrix24IoException + * @throws Bitrix24EmptyResponseException + * */ public function getNewAccessToken() { @@ -823,6 +825,10 @@ public function getNewAccessToken() * @throws Bitrix24TokenIsExpired * @throws Bitrix24TokenIsInvalid * @throws Bitrix24WrongClientException + * @throws Bitrix24PortalDeleted + * @throws Bitrix24IoException + * @throws Bitrix24EmptyResponseException + * */ public function getFirstAccessToken($code) { @@ -872,6 +878,9 @@ public function getFirstAccessToken($code) * @throws Bitrix24TokenIsExpired * @throws Bitrix24WrongClientException * @throws Bitrix24MethodNotFoundException + * @throws Bitrix24PortalDeleted + * @throws Bitrix24IoException + * @throws Bitrix24EmptyResponseException * * @return boolean */ @@ -913,6 +922,10 @@ public function isAccessTokenExpire() * @return array * * @throws Bitrix24Exception + * @throws Bitrix24Exception + * @throws Bitrix24PortalDeleted + * @throws Bitrix24IoException + * @throws Bitrix24EmptyResponseException */ public function getAvailableMethods(array $applicationScope = array(), $isFull = false) { @@ -952,6 +965,10 @@ public function getAvailableMethods(array $applicationScope = array(), $isFull = * @param bool $isFull * * @throws Bitrix24Exception + * @throws Bitrix24Exception + * @throws Bitrix24PortalDeleted + * @throws Bitrix24IoException + * @throws Bitrix24EmptyResponseException * * @return array */ diff --git a/src/bitrix24exception.php b/src/bitrix24exception.php index 5c0b78a7..f3cef761 100644 --- a/src/bitrix24exception.php +++ b/src/bitrix24exception.php @@ -5,6 +5,7 @@ * \Exception * \Bitrix24Exception — base class * \Bitrix24IoException — I/O network errors + * \Bitrix24EmptyResponseException — empty response from Bitrix24 portal * \Bitrix24ApiException — API level errors * \Bitrix24WrongClientException — Wrong client or application will be deleted from portal * \Bitrix24MethodNotFoundException — API-method not found @@ -16,10 +17,11 @@ namespace Bitrix24; class Bitrix24Exception extends \Exception {} class Bitrix24IoException extends Bitrix24Exception {} +class Bitrix24EmptyResponseException extends Bitrix24IoException {} class Bitrix24ApiException extends Bitrix24Exception {} class Bitrix24WrongClientException extends Bitrix24ApiException {} class Bitrix24MethodNotFoundException extends Bitrix24ApiException {} class Bitrix24TokenIsInvalid extends Bitrix24ApiException {} class Bitrix24TokenIsExpired extends Bitrix24ApiException {} class Bitrix24PortalDeleted extends Bitrix24ApiException {} -class Bitrix24SecurityException extends Bitrix24Exception {} +class Bitrix24SecurityException extends Bitrix24Exception {} \ No newline at end of file From 0c5e391da93ad91b404e0de5b99ef401b362bd60 Mon Sep 17 00:00:00 2001 From: Uman Shield Date: Mon, 4 Jul 2016 15:30:55 +0300 Subject: [PATCH 067/647] fix catchable error in \Bitrix24\Task\Item::update() --- src/classes/task/item.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/classes/task/item.php b/src/classes/task/item.php index c736af5b..9b7a2e6b 100644 --- a/src/classes/task/item.php +++ b/src/classes/task/item.php @@ -57,7 +57,7 @@ public function getData($taskId) */ public function update($taskId, $taskData) { - $result = $this->client->call('task.item.update', $taskId, array($taskData)); + $result = $this->client->call('task.item.update', array($taskId, $taskData)); return $result; } From 972ea9e12b136b781dca00a4406c5ac755eaa90e Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Sat, 16 Jul 2016 15:42:38 +0300 Subject: [PATCH 068/647] task#46 remove exceptions to namespace \Exceptions https://github.com/mesilov/bitrix24-php-sdk/issues/46 --- CHANGELOG.md | 24 + src/bitrix24.php | 1951 ++++++++--------- src/bitrix24exception.php | 60 + src/contracts/ibitrix24.php | 142 +- src/exceptions/bitrix24apiexception.php | 18 + .../bitrix24emptyresponseexception.php | 18 + src/exceptions/bitrix24exception.php | 32 + src/exceptions/bitrix24ioexception.php | 18 + .../bitrix24methodnotfoundexception.php | 18 + .../bitrix24paymentrequiredexception.php | 18 + .../bitrix24portaldeletedexception.php | 18 + src/exceptions/bitrix24securityexception.php | 18 + .../bitrix24tokenisexpiredexception.php | 18 + .../bitrix24tokenisinvalidexception.php | 18 + .../bitrix24wrongclientexception.php | 18 + src/stub/bitrix24.php | 148 +- tests/src/Bitrix24Test.php | 11 +- 17 files changed, 1421 insertions(+), 1127 deletions(-) create mode 100644 src/exceptions/bitrix24apiexception.php create mode 100644 src/exceptions/bitrix24emptyresponseexception.php create mode 100644 src/exceptions/bitrix24exception.php create mode 100644 src/exceptions/bitrix24ioexception.php create mode 100644 src/exceptions/bitrix24methodnotfoundexception.php create mode 100644 src/exceptions/bitrix24paymentrequiredexception.php create mode 100644 src/exceptions/bitrix24portaldeletedexception.php create mode 100644 src/exceptions/bitrix24securityexception.php create mode 100644 src/exceptions/bitrix24tokenisexpiredexception.php create mode 100644 src/exceptions/bitrix24tokenisinvalidexception.php create mode 100644 src/exceptions/bitrix24wrongclientexception.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fdcde94..56ced4a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,28 @@ # bitrix24-php-sdk change log +## 0.4.0 (16.07.2016) +* remove all exceptions in namespace `\Exceptions` see issue [Move all exceptions in namespace «Exceptions» #46](https://github.com/mesilov/bitrix24-php-sdk/issues/46) +* add class `Bitrix24\Exceptions\Bitrix24Exception` +* add class `Bitrix24\Exceptions\Bitrix24IoException` +* add class `Bitrix24\Exceptions\Bitrix24EmptyResponseException` +* add class `Bitrix24\Exceptions\Bitrix24ApiException` +* add class `Bitrix24\Exceptions\Bitrix24WrongClientException` +* add class `Bitrix24\Exceptions\Bitrix24MethodNotFoundException` +* add class `Bitrix24\Exceptions\Bitrix24TokenIsInvalidException` +* add class `Bitrix24\Exceptions\Bitrix24TokenIsExpiredException` +* add class `Bitrix24\Exceptions\Bitrix24PortalDeletedException` +* add class `Bitrix24\Exceptions\Bitrix24PaymentRequiredException` +* add class `Bitrix24\Exceptions\Bitrix24SecurityException` +* updated class `Bitrix24\Bitrix24Exception` mark as **deprecated** +* updated class `Bitrix24\Bitrix24IoException` mark as **deprecated** +* updated class `Bitrix24\Bitrix24EmptyResponseException` mark as **deprecated** +* updated class `Bitrix24\Bitrix24ApiException` mark as **deprecated** +* updated class `Bitrix24\Bitrix24WrongClientException` mark as **deprecated** +* updated class `Bitrix24\Bitrix24MethodNotFoundException` mark as **deprecated** +* updated class `Bitrix24\Bitrix24TokenIsInvalid` mark as **deprecated** +* updated class `Bitrix24\Bitrix24TokenIsExpired` mark as **deprecated** +* updated class `Bitrix24\Bitrix24PortalDeleted` mark as **deprecated** +* updated class `Bitrix24\Bitrix24SecurityException` mark as **deprecated** + ## 0.3.4 (06.06.2016) * add exception class `Bitrix24EmptyResponseException` * in class `Bitrix24` add debug information for some error types diff --git a/src/bitrix24.php b/src/bitrix24.php index 753a5179..71232438 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -3,6 +3,18 @@ use Bitrix24\Contracts\iBitrix24; +use Bitrix24\Exceptions\Bitrix24Exception; +use Bitrix24\Exceptions\Bitrix24IoException; +use Bitrix24\Exceptions\Bitrix24PaymentRequiredException; +use Bitrix24\Exceptions\Bitrix24EmptyResponseException; +use Bitrix24\Exceptions\Bitrix24ApiException; +use Bitrix24\Exceptions\Bitrix24TokenIsInvalidException; +use Bitrix24\Exceptions\Bitrix24WrongClientException; +use Bitrix24\Exceptions\Bitrix24MethodNotFoundException; +use Bitrix24\Exceptions\Bitrix24TokenIsExpiredException; +use Bitrix24\Exceptions\Bitrix24PortalDeletedException; +use Bitrix24\Exceptions\Bitrix24SecurityException; + use Psr\Log\NullLogger; use Psr\Log\LoggerInterface; @@ -13,612 +25,588 @@ */ class Bitrix24 implements iBitrix24 { - /** - * @var string SDK version - */ - const VERSION = '1.0'; - - /** - * @var string OAuth server - */ - const OAUTH_SERVER = 'oauth.bitrix.info'; - - /** - * @var string access token - */ - protected $accessToken; - - /** - * @var string refresh token - */ - protected $refreshToken; - - /** - * @var string domain - */ - protected $domain; - - /** - * @var array scope - */ - protected $applicationScope = array(); - - /** - * @var string application id - */ - protected $applicationId; - - /** - * @var string application secret - */ - protected $applicationSecret; - - /** - * @var array raw request, contain all cURL options array and API query - */ - protected $rawRequest; - - /** - * @var array, contain all api-method parameters, vill be available after call method - */ - protected $methodParameters; - - /** - * @var array request info data structure акщь curl_getinfo function - */ - protected $requestInfo; - - /** - * @var bool if true raw response from bitrix24 will be available from method getRawResponse, this is debug mode - */ - protected $isSaveRawResponse = false; - - /** - * @var array raw response from bitrix24 - */ - protected $rawResponse; - - /** - * @var string redirect URI from application settings - */ - protected $redirectUri; - - /** - * @var string portal GUID - */ - protected $memberId; - - /** - * @var array custom options for cURL - */ - protected $customCurlOptions; - - /** - * @see https://github.com/Seldaek/monolog - * @var \Monolog\Logger PSR-3 compatible logger, use only from wrappers methods log* - */ - protected $log; - - /** - * @var integer CURL request count retries - */ - protected $retriesToConnectCount; - - /** - * @var integer retries to connect timeout in microseconds - */ - protected $retriesToConnectTimeout; - - /** - * Create a object to work with Bitrix24 REST API service - * - * @param bool $isSaveRawResponse - if true raw response from bitrix24 will be available from method getRawResponse, this is debug mode - * @param null|LoggerInterface $obLogger - instance of \Monolog\Logger - * - * @throws Bitrix24Exception - * - * @return Bitrix24 - */ - public function __construct($isSaveRawResponse = false, LoggerInterface $obLogger = null) - { - if (!extension_loaded('curl')) - { - throw new Bitrix24Exception('cURL extension must be installed to use this library'); - } - if(!is_bool($isSaveRawResponse)) - { - throw new Bitrix24Exception('isSaveRawResponse flag must be boolean'); - } - $this->isSaveRawResponse = $isSaveRawResponse; - if($obLogger !== null) - { - /** - * @var \Monolog\Logger - */ - $this->log = clone $obLogger; - } - else - { - // dev/null logger - /** - * @var \Monolog\Logger - */ - $this->log = new NullLogger(); - } - $this->setRetriesToConnectCount(1); - $this->setRetriesToConnectTimeout(1000000); - } - - /** - * Get a random string to sign protected api-call. Use salt for argument "state" in secure api-call - * random string is a result of mt_rand function - * - * @return int - */ - public function getSecuritySignSalt() - { - return mt_rand(); - } - - /** - * Set member ID — portal GUID - * - * @param string $memberId - * - * @throws Bitrix24Exception - * - * @return true - */ - public function setMemberId($memberId) - { - if('' === $memberId) - { - throw new Bitrix24Exception('memberId is empty'); - } - elseif(null === $memberId) - { - throw new Bitrix24Exception('memberId is null'); - } - $this->memberId = $memberId; - return true; - } - - /** - * Get memeber ID - * - * @return string | null - */ - public function getMemberId() - { - return $this->memberId; - } - - /** - * Set redirect URI - * - * @param string $redirectUri - * - * @throws Bitrix24Exception - * - * @return true; - */ - public function setRedirectUri($redirectUri) - { - if('' === $redirectUri) - { - throw new Bitrix24Exception('redirect URI is empty'); - } - $this->redirectUri = $redirectUri; - return true; - } - - /** - * Get redirect URI - * - * @return string | null - */ - public function getRedirectUri() - { - return $this->redirectUri; - } - - /** - * Set access token - * - * @param string $accessToken - * - * @throws Bitrix24Exception - * - * @return true - */ - public function setAccessToken($accessToken) - { - if('' === $accessToken) - { - throw new Bitrix24Exception('access token is empty'); - } - $this->accessToken = $accessToken; - return true; - } - - /** - * Get access token - * - * @return string | null - */ - public function getAccessToken() - { - return $this->accessToken; - } - - /** - * Set refresh token - * - * @param $refreshToken - * - * @throws Bitrix24Exception - * - * @return true; - */ - public function setRefreshToken($refreshToken) - { - if('' === $refreshToken) - { - throw new Bitrix24Exception('refresh token is empty'); - } - $this->refreshToken = $refreshToken; - return true; - } - - /** - * Get refresh token - * - * @return string - */ - public function getRefreshToken() - { - return $this->refreshToken; - } - - /** - * Set domain - * - * @param $domain - * - * @throws Bitrix24Exception - * - * @return true; - */ - public function setDomain($domain) - { - if('' === $domain) - { - throw new Bitrix24Exception('domain is empty'); - } - $this->domain = $domain; - return true; - } - - /** - * Get domain - * - * @return string | null - */ - public function getDomain() - { - return $this->domain; - } - - /** - * Set application scope - * - * @param array $applicationScope - * - * @return boolean - * - * @throws Bitrix24Exception - */ - public function setApplicationScope(array $applicationScope) - { - if(is_array($applicationScope) && count($applicationScope)> 0) - { - $this->applicationScope = $applicationScope; - return true; - } - else - { - throw new Bitrix24Exception('application scope not set'); - } - } - - /** - * Get application scope - * - * @return string - */ - public function getApplicationScope() - { - return $this->applicationScope; - } - - /** - * Set application id - * - * @param string $applicationId - * - * @throws Bitrix24Exception - * - * @return true; - */ - public function setApplicationId($applicationId) - { - if('' === $applicationId) - { - throw new Bitrix24Exception('application id is empty'); - } - $this->applicationId = $applicationId; - return true; - }// end of SetApplicationId - - /** - * Get application id - * - * @return string - */ - public function getApplicationId() - { - return $this->applicationId; - } - - /** - * Set application secret - * - * @param string $applicationSecret - * - * @throws Bitrix24Exception - * - * @return true; - */ - public function setApplicationSecret($applicationSecret) - { - if('' === $applicationSecret) - { - throw new Bitrix24Exception('application secret is empty'); - } - $this->applicationSecret = $applicationSecret; - return true; - } - - /** - * Get application secret - * - * @return string - */ - public function getApplicationSecret() - { - return $this->applicationSecret; - } - - /** - * Set custom cURL options, overriding default ones - * - * @link http://php.net/manual/en/function.curl-setopt.php - * - * @param array $options - array(CURLOPT_XXX => value1, CURLOPT_XXX2 => value2,...) - * - * @return bool - */ - public function setCustomCurlOptions($options) - { - $this->customCurlOptions = $options; - - return true; - } - - /** - * Return raw request, contain all cURL options array and API query. Data available after you try to call method call - * numbers of array keys is const of cURL module. Example: CURLOPT_RETURNTRANSFER = 19913 - * - * @return array | null - */ - public function getRawRequest() - { - return $this->rawRequest; - } - - /** - * Return result from function curl_getinfo. Data available after you try to call method call - * - * @return array | null - */ - public function getRequestInfo() - { - return $this->requestInfo; - } - - /** - * Return additional parameters of last api-call. Data available after you try to call method call - * - * @return array | null - */ - public function getMethodParameters() - { - return $this->methodParameters; - } - - /** - * get error context - * - * @return array - */ - protected function getErrorContext() - { - return array( - // portal specific settings - 'B24_DOMAIN' => $this->getDomain(), - 'B24_MEMBER_ID' => $this->getMemberId(), - 'B24_ACCESS_TOKEN' => $this->getAccessToken(), - 'B24_REFRESH_TOKEN' => $this->getRefreshToken(), - // application settings - 'APPLICATION_SCOPE' => $this->getApplicationScope(), - 'APPLICATION_ID' => $this->getApplicationId(), - 'APPLICATION_SECRET' => $this->getApplicationSecret(), - 'REDIRECT_URI' => $this->getRedirectUri(), - // network - 'RAW_REQUEST' => $this->getRawRequest(), - 'CURL_REQUEST_INFO' => $this->getRequestInfo(), - 'RAW_RESPONSE' => $this->getRawResponse() - ); - } - - /** - * Execute a request API to Bitrix24 using cURL - * - * @param string $url - * @param array $additionalParameters - * - * @throws Bitrix24Exception - * @throws Bitrix24PortalDeleted - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * - * @return array - */ - protected function executeRequest($url, array $additionalParameters = array()) - { - $retryableErrorCodes = array( - CURLE_COULDNT_RESOLVE_HOST, - CURLE_COULDNT_CONNECT, - CURLE_HTTP_NOT_FOUND, - CURLE_READ_ERROR, - CURLE_OPERATION_TIMEOUTED, - CURLE_HTTP_POST_ERROR, - CURLE_SSL_CONNECT_ERROR - ); - - $curlOptions = array( - CURLOPT_RETURNTRANSFER => true, - CURLINFO_HEADER_OUT => true, - CURLOPT_VERBOSE => true, - CURLOPT_CONNECTTIMEOUT => 5, - CURLOPT_TIMEOUT => 5, - CURLOPT_USERAGENT => strtolower(__CLASS__.'-PHP-SDK/v'.self::VERSION), - CURLOPT_POST => true, - CURLOPT_POSTFIELDS => http_build_query($additionalParameters), - CURLOPT_URL => $url - ); - - if(is_array($this->customCurlOptions)) { - foreach($this->customCurlOptions as $customCurlOptionKey => $customCurlOptionValue) { - $curlOptions[$customCurlOptionKey] = $customCurlOptionValue; - } - } - - $this->rawRequest = $curlOptions; - $curl = curl_init(); - curl_setopt_array($curl, $curlOptions); - - $curlResult = false; - $retriesCnt = $this->retriesToConnectCount; - while($retriesCnt--){ - $this->log->debug(sprintf('try [%s] to connect to host [%s]', $retriesCnt, $this->getDomain())); - $curlResult = curl_exec($curl); - // handling network I/O errors - if(false === $curlResult) - { - $curlErrorNumber = curl_errno($curl); - $errorMsg = sprintf('in try[%s] cURL error (code %s): %s'.PHP_EOL, $retriesCnt, $curlErrorNumber, curl_error($curl)); - if (false === in_array($curlErrorNumber, $retryableErrorCodes, true) || !$retriesCnt) { - $this->log->error($errorMsg, $this->getErrorContext()); - curl_close($curl); - throw new Bitrix24IoException($errorMsg); - } - else - { - $this->log->warning($errorMsg, $this->getErrorContext()); - } - usleep($this->getRetriesToConnectTimeout()); - continue; - } - $this->requestInfo = curl_getinfo($curl); - $this->rawResponse = $curlResult; - $this->log->debug('cURL request info', array($this->getRequestInfo())); - curl_close($curl); - break; - } - - // handling URI level resource errors - switch ($this->requestInfo['http_code']) - { - case 403: - $errorMsg = sprintf('portal [%s] deleted, query aborted', $this->getDomain()); - $this->log->error($errorMsg, $this->getErrorContext()); - throw new Bitrix24PortalDeleted($errorMsg); - break; - } - - // handling server-side API errors: empty response from bitrix24 portal - if($curlResult === '') - { - $errorMsg = sprintf('empty response from portal [%s]', $this->getDomain()); - $this->log->error($errorMsg, $this->getErrorContext()); - throw new Bitrix24EmptyResponseException($errorMsg); - } - - // handling json_decode errors - $jsonResult = json_decode($curlResult, true); - unset($curlResult); - $jsonErrorCode = json_last_error(); - if(null === $jsonResult && (JSON_ERROR_NONE !== $jsonErrorCode)) - { - /** - * @todo add function json_last_error_msg() - */ - $errorMsg = 'fatal error in function json_decode.'.PHP_EOL.'Error code: '.$jsonErrorCode.PHP_EOL; - $this->log->error($errorMsg, $this->getErrorContext()); - throw new Bitrix24Exception($errorMsg); - } - return $jsonResult; - } - - /** - * Execute Bitrix24 REST API method - * - * @param string $methodName - * @param array $additionalParameters - * - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24TokenIsInvalid - * @throws Bitrix24TokenIsExpired - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24SecurityException - * @throws Bitrix24PortalDeleted - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * - * @return array - */ - public function call($methodName, array $additionalParameters = array()) - { + /** + * @var string SDK version + */ + const VERSION = '1.0'; + + /** + * @var string OAuth server + */ + const OAUTH_SERVER = 'oauth.bitrix.info'; + + /** + * @var string access token + */ + protected $accessToken; + + /** + * @var string refresh token + */ + protected $refreshToken; + + /** + * @var string domain + */ + protected $domain; + + /** + * @var array scope + */ + protected $applicationScope = array(); + + /** + * @var string application id + */ + protected $applicationId; + + /** + * @var string application secret + */ + protected $applicationSecret; + + /** + * @var array raw request, contain all cURL options array and API query + */ + protected $rawRequest; + + /** + * @var array, contain all api-method parameters, vill be available after call method + */ + protected $methodParameters; + + /** + * @var array request info data structure акщь curl_getinfo function + */ + protected $requestInfo; + + /** + * @var bool if true raw response from bitrix24 will be available from method getRawResponse, this is debug mode + */ + protected $isSaveRawResponse = false; + + /** + * @var array raw response from bitrix24 + */ + protected $rawResponse; + + /** + * @var string redirect URI from application settings + */ + protected $redirectUri; + + /** + * @var string portal GUID + */ + protected $memberId; + + /** + * @var array custom options for cURL + */ + protected $customCurlOptions; + + /** + * @see https://github.com/Seldaek/monolog + * @var \Monolog\Logger PSR-3 compatible logger, use only from wrappers methods log* + */ + protected $log; + + /** + * @var integer CURL request count retries + */ + protected $retriesToConnectCount; + + /** + * @var integer retries to connect timeout in microseconds + */ + protected $retriesToConnectTimeout; + + /** + * Create a object to work with Bitrix24 REST API service + * + * @param bool $isSaveRawResponse - if true raw response from bitrix24 will be available from method getRawResponse, this is debug mode + * @param null|LoggerInterface $obLogger - instance of \Monolog\Logger + * + * @throws Bitrix24Exception + * + * @return Bitrix24 + */ + public function __construct($isSaveRawResponse = false, LoggerInterface $obLogger = null) + { + if (!extension_loaded('curl')) { + throw new Bitrix24Exception('cURL extension must be installed to use this library'); + } + if (!is_bool($isSaveRawResponse)) { + throw new Bitrix24Exception('isSaveRawResponse flag must be boolean'); + } + $this->isSaveRawResponse = $isSaveRawResponse; + if ($obLogger !== null) { + /** + * @var \Monolog\Logger + */ + $this->log = clone $obLogger; + } else { + // dev/null logger + /** + * @var \Monolog\Logger + */ + $this->log = new NullLogger(); + } + $this->setRetriesToConnectCount(1); + $this->setRetriesToConnectTimeout(1000000); + } + + /** + * Get a random string to sign protected api-call. Use salt for argument "state" in secure api-call + * random string is a result of mt_rand function + * + * @return int + */ + public function getSecuritySignSalt() + { + return mt_rand(); + } + + /** + * Set member ID — portal GUID + * + * @param string $memberId + * + * @throws Bitrix24Exception + * + * @return true + */ + public function setMemberId($memberId) + { + if ('' === $memberId) { + throw new Bitrix24Exception('memberId is empty'); + } elseif (null === $memberId) { + throw new Bitrix24Exception('memberId is null'); + } + $this->memberId = $memberId; + return true; + } + + /** + * Get memeber ID + * + * @return string | null + */ + public function getMemberId() + { + return $this->memberId; + } + + /** + * Set redirect URI + * + * @param string $redirectUri + * + * @throws Bitrix24Exception + * + * @return true; + */ + public function setRedirectUri($redirectUri) + { + if ('' === $redirectUri) { + throw new Bitrix24Exception('redirect URI is empty'); + } + $this->redirectUri = $redirectUri; + return true; + } + + /** + * Get redirect URI + * + * @return string | null + */ + public function getRedirectUri() + { + return $this->redirectUri; + } + + /** + * Set access token + * + * @param string $accessToken + * + * @throws Bitrix24Exception + * + * @return true + */ + public function setAccessToken($accessToken) + { + if ('' === $accessToken) { + throw new Bitrix24Exception('access token is empty'); + } + $this->accessToken = $accessToken; + return true; + } + + /** + * Get access token + * + * @return string | null + */ + public function getAccessToken() + { + return $this->accessToken; + } + + /** + * Set refresh token + * + * @param $refreshToken + * + * @throws Bitrix24Exception + * + * @return true; + */ + public function setRefreshToken($refreshToken) + { + if ('' === $refreshToken) { + throw new Bitrix24Exception('refresh token is empty'); + } + $this->refreshToken = $refreshToken; + return true; + } + + /** + * Get refresh token + * + * @return string + */ + public function getRefreshToken() + { + return $this->refreshToken; + } + + /** + * Set domain + * + * @param $domain + * + * @throws Bitrix24Exception + * + * @return true; + */ + public function setDomain($domain) + { + if ('' === $domain) { + throw new Bitrix24Exception('domain is empty'); + } + $this->domain = $domain; + return true; + } + + /** + * Get domain + * + * @return string | null + */ + public function getDomain() + { + return $this->domain; + } + + /** + * Set application scope + * + * @param array $applicationScope + * + * @return boolean + * + * @throws Bitrix24Exception + */ + public function setApplicationScope(array $applicationScope) + { + if (is_array($applicationScope) && count($applicationScope) > 0) { + $this->applicationScope = $applicationScope; + return true; + } else { + throw new Bitrix24Exception('application scope not set'); + } + } + + /** + * Get application scope + * + * @return string + */ + public function getApplicationScope() + { + return $this->applicationScope; + } + + /** + * Set application id + * + * @param string $applicationId + * + * @throws Bitrix24Exception + * + * @return true; + */ + public function setApplicationId($applicationId) + { + if ('' === $applicationId) { + throw new Bitrix24Exception('application id is empty'); + } + $this->applicationId = $applicationId; + return true; + }// end of SetApplicationId + + /** + * Get application id + * + * @return string + */ + public function getApplicationId() + { + return $this->applicationId; + } + + /** + * Set application secret + * + * @param string $applicationSecret + * + * @throws Bitrix24Exception + * + * @return true; + */ + public function setApplicationSecret($applicationSecret) + { + if ('' === $applicationSecret) { + throw new Bitrix24Exception('application secret is empty'); + } + $this->applicationSecret = $applicationSecret; + return true; + } + + /** + * Get application secret + * + * @return string + */ + public function getApplicationSecret() + { + return $this->applicationSecret; + } + + /** + * Set custom cURL options, overriding default ones + * + * @link http://php.net/manual/en/function.curl-setopt.php + * + * @param array $options - array(CURLOPT_XXX => value1, CURLOPT_XXX2 => value2,...) + * + * @return bool + */ + public function setCustomCurlOptions($options) + { + $this->customCurlOptions = $options; + + return true; + } + + /** + * Return raw request, contain all cURL options array and API query. Data available after you try to call method call + * numbers of array keys is const of cURL module. Example: CURLOPT_RETURNTRANSFER = 19913 + * + * @return array | null + */ + public function getRawRequest() + { + return $this->rawRequest; + } + + /** + * Return result from function curl_getinfo. Data available after you try to call method call + * + * @return array | null + */ + public function getRequestInfo() + { + return $this->requestInfo; + } + + /** + * Return additional parameters of last api-call. Data available after you try to call method call + * + * @return array | null + */ + public function getMethodParameters() + { + return $this->methodParameters; + } + + /** + * get error context + * + * @return array + */ + protected function getErrorContext() + { + return array( + // portal specific settings + 'B24_DOMAIN' => $this->getDomain(), + 'B24_MEMBER_ID' => $this->getMemberId(), + 'B24_ACCESS_TOKEN' => $this->getAccessToken(), + 'B24_REFRESH_TOKEN' => $this->getRefreshToken(), + // application settings + 'APPLICATION_SCOPE' => $this->getApplicationScope(), + 'APPLICATION_ID' => $this->getApplicationId(), + 'APPLICATION_SECRET' => $this->getApplicationSecret(), + 'REDIRECT_URI' => $this->getRedirectUri(), + // network + 'RAW_REQUEST' => $this->getRawRequest(), + 'CURL_REQUEST_INFO' => $this->getRequestInfo(), + 'RAW_RESPONSE' => $this->getRawResponse() + ); + } + + /** + * Execute a request API to Bitrix24 using cURL + * + * @param string $url + * @param array $additionalParameters + * + * @throws Bitrix24Exception + * @throws Bitrix24PortalDeletedException + * @throws Bitrix24IoException + * @throws Bitrix24EmptyResponseException + * + * @return array + */ + protected function executeRequest($url, array $additionalParameters = array()) + { + $retryableErrorCodes = array( + CURLE_COULDNT_RESOLVE_HOST, + CURLE_COULDNT_CONNECT, + CURLE_HTTP_NOT_FOUND, + CURLE_READ_ERROR, + CURLE_OPERATION_TIMEOUTED, + CURLE_HTTP_POST_ERROR, + CURLE_SSL_CONNECT_ERROR + ); + + $curlOptions = array( + CURLOPT_RETURNTRANSFER => true, + CURLINFO_HEADER_OUT => true, + CURLOPT_VERBOSE => true, + CURLOPT_CONNECTTIMEOUT => 5, + CURLOPT_TIMEOUT => 5, + CURLOPT_USERAGENT => strtolower(__CLASS__ . '-PHP-SDK/v' . self::VERSION), + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => http_build_query($additionalParameters), + CURLOPT_URL => $url + ); + + if (is_array($this->customCurlOptions)) { + foreach ($this->customCurlOptions as $customCurlOptionKey => $customCurlOptionValue) { + $curlOptions[$customCurlOptionKey] = $customCurlOptionValue; + } + } + + $this->rawRequest = $curlOptions; + $curl = curl_init(); + curl_setopt_array($curl, $curlOptions); + + $curlResult = false; + $retriesCnt = $this->retriesToConnectCount; + while ($retriesCnt--) { + $this->log->debug(sprintf('try [%s] to connect to host [%s]', $retriesCnt, $this->getDomain())); + $curlResult = curl_exec($curl); + // handling network I/O errors + if (false === $curlResult) { + $curlErrorNumber = curl_errno($curl); + $errorMsg = sprintf('in try[%s] cURL error (code %s): %s' . PHP_EOL, $retriesCnt, $curlErrorNumber, + curl_error($curl)); + if (false === in_array($curlErrorNumber, $retryableErrorCodes, true) || !$retriesCnt) { + $this->log->error($errorMsg, $this->getErrorContext()); + curl_close($curl); + throw new Bitrix24IoException($errorMsg); + } else { + $this->log->warning($errorMsg, $this->getErrorContext()); + } + usleep($this->getRetriesToConnectTimeout()); + continue; + } + $this->requestInfo = curl_getinfo($curl); + $this->rawResponse = $curlResult; + $this->log->debug('cURL request info', array($this->getRequestInfo())); + curl_close($curl); + break; + } + + // handling URI level resource errors + switch ($this->requestInfo['http_code']) { + case 403: + $errorMsg = sprintf('portal [%s] deleted, query aborted', $this->getDomain()); + $this->log->error($errorMsg, $this->getErrorContext()); + throw new Bitrix24PortalDeletedException($errorMsg); + break; + } + + // handling server-side API errors: empty response from bitrix24 portal + if ($curlResult === '') { + $errorMsg = sprintf('empty response from portal [%s]', $this->getDomain()); + $this->log->error($errorMsg, $this->getErrorContext()); + throw new Bitrix24EmptyResponseException($errorMsg); + } + + // handling json_decode errors + $jsonResult = json_decode($curlResult, true); + unset($curlResult); + $jsonErrorCode = json_last_error(); + if (null === $jsonResult && (JSON_ERROR_NONE !== $jsonErrorCode)) { + /** + * @todo add function json_last_error_msg() + */ + $errorMsg = 'fatal error in function json_decode.' . PHP_EOL . 'Error code: ' . $jsonErrorCode . PHP_EOL; + $this->log->error($errorMsg, $this->getErrorContext()); + throw new Bitrix24Exception($errorMsg); + } + return $jsonResult; + } + + /** + * Execute Bitrix24 REST API method + * + * @param string $methodName + * @param array $additionalParameters + * + * @throws Bitrix24Exception + * @throws Bitrix24ApiException + * @throws Bitrix24TokenIsInvalidException + * @throws Bitrix24TokenIsExpiredException + * @throws Bitrix24WrongClientException + * @throws Bitrix24MethodNotFoundException + * @throws Bitrix24PaymentRequiredException + * @throws Bitrix24SecurityException + * @throws Bitrix24PortalDeletedException + * @throws Bitrix24IoException + * @throws Bitrix24EmptyResponseException + * + * @return array + */ + public function call($methodName, array $additionalParameters = array()) + { // $arAuthServerMethods = array( // 'app.info', // 'app.stat' // ); - if(null === $this->getDomain()) - { - throw new Bitrix24Exception('domain not found, you must call setDomain method before'); - } - if(null === $this->getAccessToken()) - { - throw new Bitrix24Exception('access token not found, you must call setAccessToken method before'); - } - if('' === $methodName) - { - throw new Bitrix24Exception('method name not found, you must set method name'); - } + if (null === $this->getDomain()) { + throw new Bitrix24Exception('domain not found, you must call setDomain method before'); + } + if (null === $this->getAccessToken()) { + throw new Bitrix24Exception('access token not found, you must call setAccessToken method before'); + } + if ('' === $methodName) { + throw new Bitrix24Exception('method name not found, you must set method name'); + } // if(in_array(strtolower($methodName), $arAuthServerMethods, true)) // { @@ -626,210 +614,198 @@ public function call($methodName, array $additionalParameters = array()) // } // else // { - $url = 'https://'.$this->domain.'/rest/'.$methodName; + $url = 'https://' . $this->domain . '/rest/' . $methodName; // } - $additionalParameters['auth'] = $this->accessToken; - // save method parameters for debug - $this->methodParameters = $additionalParameters; - // is secure api-call? - $isSecureCall = false; - if(array_key_exists('state', $additionalParameters)) - { - $isSecureCall = true; - } - // execute request - $this->log->info('call bitrix24 method', array( - 'BITRIX24_DOMAIN' => $this->domain, - 'METHOD_NAME' => $methodName, - 'METHOD_PARAMETERS' => $additionalParameters - )); - $requestResult = $this->executeRequest($url, $additionalParameters); - // check errors and throw exception if errors exists - $this->handleBitrix24APILevelErrors($requestResult, $methodName, $additionalParameters); - // handling security sign for secure api-call - if($isSecureCall) - { - if(array_key_exists('signature', $requestResult)) - { - // check signature structure - if (strpos($requestResult['signature'], '.') === false) - { - throw new Bitrix24SecurityException('security signature is corrupted'); - } - if(null === $this->getMemberId()) - { - throw new Bitrix24Exception('member-id not found, you must call setMemberId method before'); - } - if(null === $this->getApplicationSecret()) - { - throw new Bitrix24Exception('application secret not found, you must call setApplicationSecret method before'); - } - // prepare - $key = md5($this->getMemberId().$this->getApplicationSecret()); - $delimiterPosition = strrpos($requestResult['signature'], '.'); - $dataToDecode = substr($requestResult['signature'], 0, $delimiterPosition); - $signature = base64_decode(substr($requestResult['signature'], $delimiterPosition + 1)); - // compare signatures - $hash = hash_hmac('sha256', $dataToDecode, $key, true); - if ($hash !== $signature) - { - throw new Bitrix24SecurityException('security signatures not same, bad request'); - } - // decode - $arClearData = json_decode(base64_decode($dataToDecode), true); - // handling json_decode errors - $jsonErrorCode = json_last_error(); - if(null === $arClearData && (JSON_ERROR_NONE !== $jsonErrorCode)) - { - /** - * @todo add function json_last_error_msg() - */ - $errorMsg = 'fatal error in function json_decode.'.PHP_EOL.'Error code: '.$jsonErrorCode.PHP_EOL; - throw new Bitrix24Exception($errorMsg); - } - // merge dirty and clear data - unset($arClearData['state']); - $requestResult ['result'] = array_merge($requestResult ['result'], $arClearData); - } - else - { - throw new Bitrix24SecurityException('security signature in api-response not found'); - } - } - return $requestResult; - } - - /** - * Handling bitrix24 api-level errors - * - * @param $arRequestResult - * @param $methodName - * @param array $additionalParameters - * - * @return null - * - * @throws Bitrix24ApiException - * @throws Bitrix24TokenIsInvalid - * @throws Bitrix24TokenIsExpired - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - */ - protected function handleBitrix24APILevelErrors($arRequestResult, $methodName, array $additionalParameters = array()) - { - if (array_key_exists('error', $arRequestResult)) - { - $errorMsg = sprintf('%s - %s in call [%s] for domain [%s]', - $arRequestResult['error'], - (array_key_exists('error_description', $arRequestResult) ? $arRequestResult['error_description'] : ''), - $methodName, - $this->getDomain()); - $this->log->error($errorMsg, $this->getErrorContext()); - // throw specific API-level exceptions - switch(strtoupper(trim($arRequestResult['error']))) - { - case 'WRONG_CLIENT': - throw new Bitrix24WrongClientException($errorMsg); - case 'ERROR_METHOD_NOT_FOUND': - throw new Bitrix24MethodNotFoundException($errorMsg); - case 'INVALID_TOKEN': - throw new Bitrix24TokenIsInvalid($errorMsg); - case 'EXPIRED_TOKEN': - throw new Bitrix24TokenIsExpired($errorMsg); - default: - throw new Bitrix24ApiException($errorMsg); - } - } - return null; - } - - /** - * Get raw response from Bitrix24 before json_decode call, method available only in debug mode. - * To activate debug mode you must before set to true flag isSaveRawResponse in class construct - * - * @return string | null - */ - public function getRawResponse() - { - return $this->rawResponse; - } - - /** - * Get new access token - * - * @return array - * - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24TokenIsInvalid - * @throws Bitrix24TokenIsExpired - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24PortalDeleted - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * - */ - public function getNewAccessToken() - { - $applicationId = $this->getApplicationId(); - $applicationSecret = $this->getApplicationSecret(); - $refreshToken = $this->getRefreshToken(); - $applicationScope = $this->getApplicationScope(); - $redirectUri = $this->getRedirectUri(); - - if(null === $applicationId) - { - throw new Bitrix24Exception('application id not found, you must call setApplicationId method before'); - } - elseif(null === $applicationSecret) - { - throw new Bitrix24Exception('application id not found, you must call setApplicationSecret method before'); - } - elseif(null === $refreshToken) - { - throw new Bitrix24Exception('application id not found, you must call setRefreshToken method before'); - } - elseif(0 === count($applicationScope)) - { - throw new Bitrix24Exception('application scope not found, you must call setApplicationScope method before'); - } - elseif(null === $redirectUri) - { - throw new Bitrix24Exception('application redirect URI not found, you must call setRedirectUri method before'); - } + $additionalParameters['auth'] = $this->accessToken; + // save method parameters for debug + $this->methodParameters = $additionalParameters; + // is secure api-call? + $isSecureCall = false; + if (array_key_exists('state', $additionalParameters)) { + $isSecureCall = true; + } + // execute request + $this->log->info('call bitrix24 method', array( + 'BITRIX24_DOMAIN' => $this->domain, + 'METHOD_NAME' => $methodName, + 'METHOD_PARAMETERS' => $additionalParameters + )); + $requestResult = $this->executeRequest($url, $additionalParameters); + // check errors and throw exception if errors exists + $this->handleBitrix24APILevelErrors($requestResult, $methodName, $additionalParameters); + // handling security sign for secure api-call + if ($isSecureCall) { + if (array_key_exists('signature', $requestResult)) { + // check signature structure + if (strpos($requestResult['signature'], '.') === false) { + throw new Bitrix24SecurityException('security signature is corrupted'); + } + if (null === $this->getMemberId()) { + throw new Bitrix24Exception('member-id not found, you must call setMemberId method before'); + } + if (null === $this->getApplicationSecret()) { + throw new Bitrix24Exception('application secret not found, you must call setApplicationSecret method before'); + } + // prepare + $key = md5($this->getMemberId() . $this->getApplicationSecret()); + $delimiterPosition = strrpos($requestResult['signature'], '.'); + $dataToDecode = substr($requestResult['signature'], 0, $delimiterPosition); + $signature = base64_decode(substr($requestResult['signature'], $delimiterPosition + 1)); + // compare signatures + $hash = hash_hmac('sha256', $dataToDecode, $key, true); + if ($hash !== $signature) { + throw new Bitrix24SecurityException('security signatures not same, bad request'); + } + // decode + $arClearData = json_decode(base64_decode($dataToDecode), true); + // handling json_decode errors + $jsonErrorCode = json_last_error(); + if (null === $arClearData && (JSON_ERROR_NONE !== $jsonErrorCode)) { + /** + * @todo add function json_last_error_msg() + */ + $errorMsg = 'fatal error in function json_decode.' . PHP_EOL . 'Error code: ' . $jsonErrorCode . PHP_EOL; + throw new Bitrix24Exception($errorMsg); + } + // merge dirty and clear data + unset($arClearData['state']); + $requestResult ['result'] = array_merge($requestResult ['result'], $arClearData); + } else { + throw new Bitrix24SecurityException('security signature in api-response not found'); + } + } + return $requestResult; + } + + /** + * Handling bitrix24 api-level errors + * + * @param $arRequestResult + * @param $methodName + * @param array $additionalParameters + * + * @return null + * + * @throws Bitrix24ApiException + * @throws Bitrix24TokenIsInvalidException + * @throws Bitrix24TokenIsExpiredException + * @throws Bitrix24WrongClientException + * @throws Bitrix24MethodNotFoundException + * @throws Bitrix24PaymentRequiredException + */ + protected function handleBitrix24APILevelErrors( + $arRequestResult, + $methodName, + array $additionalParameters = array() + ) { + if (array_key_exists('error', $arRequestResult)) { + $errorMsg = sprintf('%s - %s in call [%s] for domain [%s]', + $arRequestResult['error'], + (array_key_exists('error_description', $arRequestResult) ? $arRequestResult['error_description'] : ''), + $methodName, + $this->getDomain()); + $this->log->error($errorMsg, $this->getErrorContext()); + // throw specific API-level exceptions + switch (strtoupper(trim($arRequestResult['error']))) { + case 'WRONG_CLIENT': + case 'ERROR_OAUTH': + throw new Bitrix24WrongClientException($errorMsg); + case 'ERROR_METHOD_NOT_FOUND': + throw new Bitrix24MethodNotFoundException($errorMsg); + case 'INVALID_TOKEN': + case 'INVALID_GRANT': + throw new Bitrix24TokenIsInvalidException($errorMsg); + case 'EXPIRED_TOKEN': + throw new Bitrix24TokenIsExpiredException($errorMsg); + case 'PAYMENT_REQUIRED': + throw new Bitrix24PaymentRequiredException($errorMsg); + default: + throw new Bitrix24ApiException($errorMsg); + } + } + return null; + } + + /** + * Get raw response from Bitrix24 before json_decode call, method available only in debug mode. + * To activate debug mode you must before set to true flag isSaveRawResponse in class construct + * + * @return string | null + */ + public function getRawResponse() + { + return $this->rawResponse; + } + + /** + * Get new access token + * + * @return array + * + * @throws Bitrix24Exception + * @throws Bitrix24ApiException + * @throws Bitrix24PortalDeletedException + * @throws Bitrix24IoException + * @throws Bitrix24EmptyResponseException + * @throws Bitrix24TokenIsInvalidException + * @throws Bitrix24TokenIsExpiredException + * @throws Bitrix24WrongClientException + * @throws Bitrix24MethodNotFoundException + * @throws Bitrix24PaymentRequiredException + * + */ + public function getNewAccessToken() + { + $applicationId = $this->getApplicationId(); + $applicationSecret = $this->getApplicationSecret(); + $refreshToken = $this->getRefreshToken(); + $applicationScope = $this->getApplicationScope(); + $redirectUri = $this->getRedirectUri(); + + if (null === $applicationId) { + throw new Bitrix24Exception('application id not found, you must call setApplicationId method before'); + } elseif (null === $applicationSecret) { + throw new Bitrix24Exception('application id not found, you must call setApplicationSecret method before'); + } elseif (null === $refreshToken) { + throw new Bitrix24Exception('application id not found, you must call setRefreshToken method before'); + } elseif (0 === count($applicationScope)) { + throw new Bitrix24Exception('application scope not found, you must call setApplicationScope method before'); + } elseif (null === $redirectUri) { + throw new Bitrix24Exception('application redirect URI not found, you must call setRedirectUri method before'); + } // $url = 'https://'.self::OAUTH_SERVER.'/oauth/token/'. - $url = 'https://'.$this->getDomain().'/oauth/token/'. - '?client_id='.urlencode($applicationId). - '&grant_type=refresh_token'. - '&client_secret='.$applicationSecret. - '&refresh_token='.$refreshToken. - '&redirect_uri='.urlencode($redirectUri); - $requestResult = $this->executeRequest($url); - // handling bitrix24 api-level errors - $this->handleBitrix24APILevelErrors($requestResult, 'refresh access token'); - return $requestResult; - } - - /** - * Authorize and get first access token - * - * @param $code - * - * @return array - * - * @throws Bitrix24ApiException - * @throws Bitrix24Exception - * @throws Bitrix24IoException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24TokenIsExpired - * @throws Bitrix24TokenIsInvalid - * @throws Bitrix24WrongClientException - * @throws Bitrix24PortalDeleted - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * - */ + $url = 'https://' . $this->getDomain() . '/oauth/token/' . + '?client_id=' . urlencode($applicationId) . + '&grant_type=refresh_token' . + '&client_secret=' . $applicationSecret . + '&refresh_token=' . $refreshToken . + '&redirect_uri=' . urlencode($redirectUri); + $requestResult = $this->executeRequest($url); + // handling bitrix24 api-level errors + $this->handleBitrix24APILevelErrors($requestResult, 'refresh access token'); + return $requestResult; + } + + /** + * Authorize and get first access token + * + * @param $code + * + * @return array + * + * @throws Bitrix24Exception + * @throws Bitrix24ApiException + * @throws Bitrix24PortalDeletedException + * @throws Bitrix24IoException + * @throws Bitrix24EmptyResponseException + * @throws Bitrix24TokenIsInvalidException + * @throws Bitrix24TokenIsExpiredException + * @throws Bitrix24WrongClientException + * @throws Bitrix24MethodNotFoundException + * @throws Bitrix24PaymentRequiredException + * + */ public function getFirstAccessToken($code) { $applicationId = $this->getApplicationId(); @@ -837,30 +813,23 @@ public function getFirstAccessToken($code) $applicationScope = $this->getApplicationScope(); $redirectUri = $this->getRedirectUri(); - if(null === $applicationId) - { + if (null === $applicationId) { throw new Bitrix24Exception('application id not found, you must call setApplicationId method before'); - } - elseif(null === $applicationSecret) - { + } elseif (null === $applicationSecret) { throw new Bitrix24Exception('application id not found, you must call setApplicationSecret method before'); - } - elseif(0 === count($applicationScope)) - { + } elseif (0 === count($applicationScope)) { throw new Bitrix24Exception('application scope not found, you must call setApplicationScope method before'); - } - elseif(null === $redirectUri) - { + } elseif (null === $redirectUri) { throw new Bitrix24Exception('application redirect URI not found, you must call setRedirectUri method before'); } // $url = 'https://'.self::OAUTH_SERVER.'/oauth/token/'. - $url = 'https://'.$this->getDomain().'/oauth/token/'. - '?client_id='.urlencode($applicationId). - '&grant_type=authorization_code'. - '&client_secret='.$applicationSecret. - '&redirect_uri='.urlencode($redirectUri). - '&code='.urlencode($code); + $url = 'https://' . $this->getDomain() . '/oauth/token/' . + '?client_id=' . urlencode($applicationId) . + '&grant_type=authorization_code' . + '&client_secret=' . $applicationSecret . + '&redirect_uri=' . urlencode($redirectUri) . + '&code=' . urlencode($code); $requestResult = $this->executeRequest($url); // handling bitrix24 api-level errors @@ -868,187 +837,167 @@ public function getFirstAccessToken($code) return $requestResult; } - /** - * Check is access token expire, call list of all available api-methods from B24 portal with current access token - * if we have an error code expired_token then return true else return false - * - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24TokenIsInvalid - * @throws Bitrix24TokenIsExpired - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24PortalDeleted - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * - * @return boolean - */ - public function isAccessTokenExpire() - { - $isTokenExpire = false; - $accessToken = $this->getAccessToken(); - $domain = $this->getDomain(); - - if(null === $domain) - { - throw new Bitrix24Exception('domain not found, you must call setDomain method before'); - } - elseif(null === $accessToken) - { - throw new Bitrix24Exception('application id not found, you must call setAccessToken method before'); - } + /** + * Check is access token expire, call list of all available api-methods from B24 portal with current access token + * if we have an error code expired_token then return true else return false + * + * @throws Bitrix24Exception + * @throws Bitrix24ApiException + * @throws Bitrix24PortalDeletedException + * @throws Bitrix24IoException + * @throws Bitrix24EmptyResponseException + * @throws Bitrix24TokenIsInvalidException + * @throws Bitrix24TokenIsExpiredException + * @throws Bitrix24WrongClientException + * @throws Bitrix24MethodNotFoundException + * @throws Bitrix24PaymentRequiredException + * + * @return boolean + */ + public function isAccessTokenExpire() + { + $isTokenExpire = false; + $accessToken = $this->getAccessToken(); + $domain = $this->getDomain(); + + if (null === $domain) { + throw new Bitrix24Exception('domain not found, you must call setDomain method before'); + } elseif (null === $accessToken) { + throw new Bitrix24Exception('application id not found, you must call setAccessToken method before'); + } // $url = 'https://'.self::OAUTH_SERVER.'/rest/app.info?auth='.$accessToken; - $url = 'https://'.$domain.'/rest/app.info?auth='.$accessToken; - $requestResult = $this->executeRequest($url); - if(in_array($requestResult['error'], array('expired_token', 'invalid_token', 'WRONG_TOKEN'), false)) - { - $isTokenExpire = true; - } - else - { - // handle other errors - $this->handleBitrix24APILevelErrors($requestResult, 'app.info'); - } - return $isTokenExpire; - }// end of isTokenExpire - - /** - * Get list of all methods available for current application - * - * @param array | null $applicationScope - * @param bool $isFull - * - * @return array - * - * @throws Bitrix24Exception - * @throws Bitrix24Exception - * @throws Bitrix24PortalDeleted - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - */ - public function getAvailableMethods(array $applicationScope = array(), $isFull = false) - { - $accessToken = $this->getAccessToken(); - $domain = $this->getDomain(); - - if(null === $domain) - { - throw new Bitrix24Exception('domain not found, you must call setDomain method before'); - } - elseif(null === $accessToken) - { - throw new Bitrix24Exception('application id not found, you must call setAccessToken method before'); - } - - $showAll = ''; - if(TRUE === $isFull) - { - $showAll = '&full=true'; - } - $scope=''; - if(null === $applicationScope) - { - $scope = '&scope'; - } - elseif(count(array_unique($applicationScope)) > 0) - { - $scope = '&scope='.implode(',', array_map('urlencode', array_unique($applicationScope))); - } - $url = 'https://'.$domain.'/rest/methods.json?auth='.$accessToken.$showAll.$scope; - return $this->executeRequest($url); - } - - /** - * get list of scope for current application from bitrix24 api - * - * @param bool $isFull - * - * @throws Bitrix24Exception - * @throws Bitrix24Exception - * @throws Bitrix24PortalDeleted - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * - * @return array - */ - public function getScope($isFull=false) - { - $accessToken = $this->getAccessToken(); - $domain = $this->getDomain(); - - if(null === $domain) - { - throw new Bitrix24Exception('domain not found, you must call setDomain method before'); - } - elseif(null === $accessToken) - { - throw new Bitrix24Exception('application id not found, you must call setAccessToken method before'); - } - $showAll = ''; - if(TRUE === $isFull) - { - $showAll = '&full=true'; - } - $url = 'https://'.$domain.'/rest/scope.json?auth='.$accessToken.$showAll; - return $this->executeRequest($url); - } - - /** - * set CURL request count retries - * @param $retriesCnt - * - * @return boolean - * - * @throws Bitrix24Exception - */ - public function setRetriesToConnectCount($retriesCnt = 1) - { - $this->log->debug(sprintf('set retries to connect count %s', $retriesCnt)); - if(!is_int($retriesCnt)) - { - throw new Bitrix24Exception('retries to connect count must be an integer'); - } - $this->retriesToConnectCount = (int) $retriesCnt; - return true; - } - - /** - * set retries to connect timeout in microseconds - * @param int $microseconds - - * @return bool - - * @throws Bitrix24Exception - */ - public function setRetriesToConnectTimeout($microseconds = 1000000) - { - $this->log->debug(sprintf('set retries to connect count %s', $microseconds)); - if(!is_numeric($microseconds)) - { - throw new Bitrix24Exception('retries to connect count must be an integer'); - } - $this->retriesToConnectTimeout = $microseconds; - return true; - } - - /** - * get CURL request count retries - * - * @return int - */ - public function getRetriesToConnectCount() - { - return $this->retriesToConnectCount; - } - - /** - * get retries to connect timeout in microseconds - * - * @return mixed - */ - public function getRetriesToConnectTimeout() - { - return $this->retriesToConnectTimeout; - } + $url = 'https://' . $domain . '/rest/app.info?auth=' . $accessToken; + $requestResult = $this->executeRequest($url); + if (in_array($requestResult['error'], array('expired_token', 'invalid_token', 'WRONG_TOKEN'), false)) { + $isTokenExpire = true; + } else { + // handle other errors + $this->handleBitrix24APILevelErrors($requestResult, 'app.info'); + } + return $isTokenExpire; + }// end of isTokenExpire + + /** + * Get list of all methods available for current application + * + * @param array | null $applicationScope + * @param bool $isFull + * + * @return array + * + * @throws Bitrix24Exception + * @throws Bitrix24Exception + * @throws Bitrix24PortalDeletedException + * @throws Bitrix24IoException + * @throws Bitrix24EmptyResponseException + */ + public function getAvailableMethods(array $applicationScope = array(), $isFull = false) + { + $accessToken = $this->getAccessToken(); + $domain = $this->getDomain(); + + if (null === $domain) { + throw new Bitrix24Exception('domain not found, you must call setDomain method before'); + } elseif (null === $accessToken) { + throw new Bitrix24Exception('application id not found, you must call setAccessToken method before'); + } + + $showAll = ''; + if (true === $isFull) { + $showAll = '&full=true'; + } + $scope = ''; + if (null === $applicationScope) { + $scope = '&scope'; + } elseif (count(array_unique($applicationScope)) > 0) { + $scope = '&scope=' . implode(',', array_map('urlencode', array_unique($applicationScope))); + } + $url = 'https://' . $domain . '/rest/methods.json?auth=' . $accessToken . $showAll . $scope; + return $this->executeRequest($url); + } + + /** + * get list of scope for current application from bitrix24 api + * + * @param bool $isFull + * + * @throws Bitrix24Exception + * @throws Bitrix24Exception + * @throws Bitrix24PortalDeletedException + * @throws Bitrix24IoException + * @throws Bitrix24EmptyResponseException + * + * @return array + */ + public function getScope($isFull = false) + { + $accessToken = $this->getAccessToken(); + $domain = $this->getDomain(); + + if (null === $domain) { + throw new Bitrix24Exception('domain not found, you must call setDomain method before'); + } elseif (null === $accessToken) { + throw new Bitrix24Exception('application id not found, you must call setAccessToken method before'); + } + $showAll = ''; + if (true === $isFull) { + $showAll = '&full=true'; + } + $url = 'https://' . $domain . '/rest/scope.json?auth=' . $accessToken . $showAll; + return $this->executeRequest($url); + } + + /** + * set CURL request count retries + * @param $retriesCnt + * + * @return boolean + * + * @throws Bitrix24Exception + */ + public function setRetriesToConnectCount($retriesCnt = 1) + { + $this->log->debug(sprintf('set retries to connect count %s', $retriesCnt)); + if (!is_int($retriesCnt)) { + throw new Bitrix24Exception('retries to connect count must be an integer'); + } + $this->retriesToConnectCount = (int)$retriesCnt; + return true; + } + + /** + * set retries to connect timeout in microseconds + * @param int $microseconds + * @return bool + * @throws Bitrix24Exception + */ + public function setRetriesToConnectTimeout($microseconds = 1000000) + { + $this->log->debug(sprintf('set retries to connect count %s', $microseconds)); + if (!is_numeric($microseconds)) { + throw new Bitrix24Exception('retries to connect count must be an integer'); + } + $this->retriesToConnectTimeout = $microseconds; + return true; + } + + /** + * get CURL request count retries + * + * @return int + */ + public function getRetriesToConnectCount() + { + return $this->retriesToConnectCount; + } + + /** + * get retries to connect timeout in microseconds + * + * @return mixed + */ + public function getRetriesToConnectTimeout() + { + return $this->retriesToConnectTimeout; + } } \ No newline at end of file diff --git a/src/bitrix24exception.php b/src/bitrix24exception.php index f3cef761..81292f1f 100644 --- a/src/bitrix24exception.php +++ b/src/bitrix24exception.php @@ -15,13 +15,73 @@ * \Bitrix24SecurityException — Security errors for protected methods */ namespace Bitrix24; + +/** + * Class Bitrix24Exception + * @package Bitrix24 + * @deprecated use \Bitrix24\Exceptions\Bitrix24Exception + */ class Bitrix24Exception extends \Exception {} + +/** + * Class Bitrix24IoException + * @package Bitrix24 + * @deprecated use \Bitrix24\Exceptions\Bitrix24IoException + */ class Bitrix24IoException extends Bitrix24Exception {} + +/** + * Class Bitrix24EmptyResponseException + * @package Bitrix24 + * @deprecated use \Bitrix24\Exceptions\Bitrix24EmptyResponseException + */ class Bitrix24EmptyResponseException extends Bitrix24IoException {} + +/** + * Class Bitrix24ApiException + * @package Bitrix24 + * @deprecated use \Bitrix24\Exceptions\Bitrix24ApiException + */ class Bitrix24ApiException extends Bitrix24Exception {} + +/** + * Class Bitrix24WrongClientException + * @package Bitrix24 + * @deprecated use \Bitrix24\Exceptions\Bitrix24WrongClientException + */ class Bitrix24WrongClientException extends Bitrix24ApiException {} + +/** + * Class Bitrix24MethodNotFoundException + * @package Bitrix24 + * @deprecated use \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + */ class Bitrix24MethodNotFoundException extends Bitrix24ApiException {} + +/** + * Class Bitrix24TokenIsInvalid + * @package Bitrix24 + * @deprecated use \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + */ class Bitrix24TokenIsInvalid extends Bitrix24ApiException {} + +/** + * Class Bitrix24TokenIsExpired + * @package Bitrix24 + * @deprecated use \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + */ class Bitrix24TokenIsExpired extends Bitrix24ApiException {} + +/** + * Class Bitrix24PortalDeleted + * @package Bitrix24 + * @deprecated use \Bitrix24\Exceptions\Bitrix24PortalDeletedException + */ class Bitrix24PortalDeleted extends Bitrix24ApiException {} + +/** + * Class Bitrix24SecurityException + * @package Bitrix24 + * @deprecated use \Bitrix24\Exceptions\Bitrix24SecurityException + */ class Bitrix24SecurityException extends Bitrix24Exception {} \ No newline at end of file diff --git a/src/contracts/ibitrix24.php b/src/contracts/ibitrix24.php index 31f63566..f980caa7 100644 --- a/src/contracts/ibitrix24.php +++ b/src/contracts/ibitrix24.php @@ -8,16 +8,19 @@ namespace Bitrix24\Contracts; use Bitrix24\Bitrix24; -use Bitrix24\Bitrix24Exception; -use Bitrix24\Bitrix24IoException; -use Bitrix24\Bitrix24ApiException; -use Bitrix24\Bitrix24WrongClientException; -use Bitrix24\Bitrix24MethodNotFoundException; -use Bitrix24\Bitrix24TokenIsInvalid; -use Bitrix24\Bitrix24TokenIsExpired; -use Bitrix24\Bitrix24SecurityException; - -use Bitrix24\Stub\Logger; +use Bitrix24\Exceptions\Bitrix24Exception; +use Bitrix24\Exceptions\Bitrix24IoException; +use Bitrix24\Exceptions\Bitrix24PaymentRequiredException; +use Bitrix24\Exceptions\Bitrix24EmptyResponseException; +use Bitrix24\Exceptions\Bitrix24ApiException; +use Bitrix24\Exceptions\Bitrix24TokenIsInvalidException; +use Bitrix24\Exceptions\Bitrix24WrongClientException; +use Bitrix24\Exceptions\Bitrix24MethodNotFoundException; +use Bitrix24\Exceptions\Bitrix24TokenIsExpiredException; +use Bitrix24\Exceptions\Bitrix24PortalDeletedException; +use Bitrix24\Exceptions\Bitrix24SecurityException; + + use Psr\Log\LoggerInterface; /** @@ -176,19 +179,26 @@ public function getRequestInfo(); */ public function getMethodParameters(); - /** - * Execute Bitrix24 REST API method - * @param string $methodName - * @param array $additionalParameters - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24TokenIsInvalid - * @throws Bitrix24TokenIsExpired - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24SecurityException - * @return array - */ + /** + * Execute Bitrix24 REST API method + * + * @param string $methodName + * @param array $additionalParameters + * + * @throws Bitrix24Exception + * @throws Bitrix24ApiException + * @throws Bitrix24TokenIsInvalidException + * @throws Bitrix24TokenIsExpiredException + * @throws Bitrix24WrongClientException + * @throws Bitrix24MethodNotFoundException + * @throws Bitrix24PaymentRequiredException + * @throws Bitrix24SecurityException + * @throws Bitrix24PortalDeletedException + * @throws Bitrix24IoException + * @throws Bitrix24EmptyResponseException + * + * @return array + */ public function call($methodName, array $additionalParameters = array()); /** @@ -199,43 +209,63 @@ public function call($methodName, array $additionalParameters = array()); */ public function getRawResponse(); - /** - * Get new access token - * @return array - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24TokenIsInvalid - * @throws Bitrix24TokenIsExpired - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - */ + /** + * Get new access token + * + * @return array + * + * @throws Bitrix24Exception + * @throws Bitrix24ApiException + * @throws Bitrix24PortalDeletedException + * @throws Bitrix24IoException + * @throws Bitrix24EmptyResponseException + * @throws Bitrix24TokenIsInvalidException + * @throws Bitrix24TokenIsExpiredException + * @throws Bitrix24WrongClientException + * @throws Bitrix24MethodNotFoundException + * @throws Bitrix24PaymentRequiredException + * + */ public function getNewAccessToken(); - /** - * Authorize and get first access token - * @param $code - * @return array - * @throws Bitrix24ApiException - * @throws Bitrix24Exception - * @throws Bitrix24IoException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24TokenIsExpired - * @throws Bitrix24TokenIsInvalid - * @throws Bitrix24WrongClientException - */ + /** + * Authorize and get first access token + * + * @param $code + * + * @return array + * + * @throws Bitrix24Exception + * @throws Bitrix24ApiException + * @throws Bitrix24PortalDeletedException + * @throws Bitrix24IoException + * @throws Bitrix24EmptyResponseException + * @throws Bitrix24TokenIsInvalidException + * @throws Bitrix24TokenIsExpiredException + * @throws Bitrix24WrongClientException + * @throws Bitrix24MethodNotFoundException + * @throws Bitrix24PaymentRequiredException + * + */ public function getFirstAccessToken($code); - /** - * Check is access token expire, call list of all available api-methods from B24 portal with current access token - * if we have an error code expired_token then return true else return false - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24TokenIsInvalid - * @throws Bitrix24TokenIsExpired - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @return boolean - */ + /** + * Check is access token expire, call list of all available api-methods from B24 portal with current access token + * if we have an error code expired_token then return true else return false + * + * @throws Bitrix24Exception + * @throws Bitrix24ApiException + * @throws Bitrix24PortalDeletedException + * @throws Bitrix24IoException + * @throws Bitrix24EmptyResponseException + * @throws Bitrix24TokenIsInvalidException + * @throws Bitrix24TokenIsExpiredException + * @throws Bitrix24WrongClientException + * @throws Bitrix24MethodNotFoundException + * @throws Bitrix24PaymentRequiredException + * + * @return boolean + */ public function isAccessTokenExpire(); /** diff --git a/src/exceptions/bitrix24apiexception.php b/src/exceptions/bitrix24apiexception.php new file mode 100644 index 00000000..04c2b405 --- /dev/null +++ b/src/exceptions/bitrix24apiexception.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Bitrix24\Exceptions; + +/** + * Class Bitrix24PaymentRequiredException + * @package Bitrix24 + */ +class Bitrix24ApiException extends Bitrix24Exception +{ +} \ No newline at end of file diff --git a/src/exceptions/bitrix24emptyresponseexception.php b/src/exceptions/bitrix24emptyresponseexception.php new file mode 100644 index 00000000..1342d227 --- /dev/null +++ b/src/exceptions/bitrix24emptyresponseexception.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Bitrix24\Exceptions; + +/** + * Class Bitrix24IOException + * @package Bitrix24 + */ +class Bitrix24EmptyResponseException extends Bitrix24IoException +{ +} \ No newline at end of file diff --git a/src/exceptions/bitrix24exception.php b/src/exceptions/bitrix24exception.php new file mode 100644 index 00000000..9b867bc3 --- /dev/null +++ b/src/exceptions/bitrix24exception.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Bitrix24\Exceptions; + +/** + * Class Bitrix24Exception + * + * \Exception + * \Bitrix24Exception — base class + * \Bitrix24IoException — I/O network errors + * \Bitrix24EmptyResponseException — empty response from Bitrix24 portal + * \Bitrix24ApiException — API level errors + * \Bitrix24WrongClientException — Wrong client or application will be deleted from portal + * \Bitrix24MethodNotFoundException — API-method not found + * \Bitrix24TokenIsInvalidException — The access token provided is invalid + * \Bitrix24TokenIsExpiredException — The access token provided has expired + * \Bitrix24PortalDeletedException — Bitrix24 portal deleted + * \Bitrix24PaymentRequiredException — Bitrix24 application payment required + * \Bitrix24SecurityException — Security errors for protected methods + * + * @package Bitrix24\Exceptions + */ +class Bitrix24Exception extends \Exception +{ +} \ No newline at end of file diff --git a/src/exceptions/bitrix24ioexception.php b/src/exceptions/bitrix24ioexception.php new file mode 100644 index 00000000..5817969b --- /dev/null +++ b/src/exceptions/bitrix24ioexception.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Bitrix24\Exceptions; + +/** + * Class Bitrix24IoException + * @package Bitrix24 + */ +class Bitrix24IoException extends Bitrix24Exception +{ +} \ No newline at end of file diff --git a/src/exceptions/bitrix24methodnotfoundexception.php b/src/exceptions/bitrix24methodnotfoundexception.php new file mode 100644 index 00000000..78116a25 --- /dev/null +++ b/src/exceptions/bitrix24methodnotfoundexception.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Bitrix24\Exceptions; + +/** + * Class Bitrix24WrongClientException + * @package Bitrix24 + */ +class Bitrix24MethodNotFoundException extends Bitrix24ApiException +{ +} \ No newline at end of file diff --git a/src/exceptions/bitrix24paymentrequiredexception.php b/src/exceptions/bitrix24paymentrequiredexception.php new file mode 100644 index 00000000..dce1d1a0 --- /dev/null +++ b/src/exceptions/bitrix24paymentrequiredexception.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Bitrix24\Exceptions; + +/** + * Class Bitrix24PaymentRequiredException + * @package Bitrix24 + */ +class Bitrix24PaymentRequiredException extends Bitrix24ApiException +{ +} \ No newline at end of file diff --git a/src/exceptions/bitrix24portaldeletedexception.php b/src/exceptions/bitrix24portaldeletedexception.php new file mode 100644 index 00000000..9001a5cc --- /dev/null +++ b/src/exceptions/bitrix24portaldeletedexception.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Bitrix24\Exceptions; + +/** + * Class Bitrix24PortalDeletedException + * @package Bitrix24 + */ +class Bitrix24PortalDeletedException extends Bitrix24ApiException +{ +} \ No newline at end of file diff --git a/src/exceptions/bitrix24securityexception.php b/src/exceptions/bitrix24securityexception.php new file mode 100644 index 00000000..aeda62ce --- /dev/null +++ b/src/exceptions/bitrix24securityexception.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Bitrix24\Exceptions; + +/** + * Class Bitrix24SecurityException + * @package Bitrix24 + */ +class Bitrix24SecurityException extends Bitrix24Exception +{ +} \ No newline at end of file diff --git a/src/exceptions/bitrix24tokenisexpiredexception.php b/src/exceptions/bitrix24tokenisexpiredexception.php new file mode 100644 index 00000000..9c6fa130 --- /dev/null +++ b/src/exceptions/bitrix24tokenisexpiredexception.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Bitrix24\Exceptions; + +/** + * Class Bitrix24TokenIsExpiredException + * @package Bitrix24 + */ +class Bitrix24TokenIsExpiredException extends Bitrix24ApiException +{ +} \ No newline at end of file diff --git a/src/exceptions/bitrix24tokenisinvalidexception.php b/src/exceptions/bitrix24tokenisinvalidexception.php new file mode 100644 index 00000000..28c18571 --- /dev/null +++ b/src/exceptions/bitrix24tokenisinvalidexception.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Bitrix24\Exceptions; + +/** + * Class Bitrix24TokenIsInvalidException + * @package Bitrix24 + */ +class Bitrix24TokenIsInvalidException extends Bitrix24ApiException +{ +} \ No newline at end of file diff --git a/src/exceptions/bitrix24wrongclientexception.php b/src/exceptions/bitrix24wrongclientexception.php new file mode 100644 index 00000000..92c280a9 --- /dev/null +++ b/src/exceptions/bitrix24wrongclientexception.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Bitrix24\Exceptions; + +/** + * Class Bitrix24WrongClientException + * @package Bitrix24 + */ +class Bitrix24WrongClientException extends Bitrix24ApiException +{ +} \ No newline at end of file diff --git a/src/stub/bitrix24.php b/src/stub/bitrix24.php index 2b99b576..ceeadaf8 100644 --- a/src/stub/bitrix24.php +++ b/src/stub/bitrix24.php @@ -4,14 +4,17 @@ use Bitrix24\Contracts\iBitrix24; use Psr\Log\LoggerInterface; -use Bitrix24\Bitrix24Exception; -use Bitrix24\Bitrix24IoException; -use Bitrix24\Bitrix24ApiException; -use Bitrix24\Bitrix24WrongClientException; -use Bitrix24\Bitrix24MethodNotFoundException; -use Bitrix24\Bitrix24TokenIsInvalid; -use Bitrix24\Bitrix24TokenIsExpired; -use Bitrix24\Bitrix24SecurityException; +use Bitrix24\Exceptions\Bitrix24Exception; +use Bitrix24\Exceptions\Bitrix24IoException; +use Bitrix24\Exceptions\Bitrix24PaymentRequiredException; +use Bitrix24\Exceptions\Bitrix24EmptyResponseException; +use Bitrix24\Exceptions\Bitrix24ApiException; +use Bitrix24\Exceptions\Bitrix24TokenIsInvalidException; +use Bitrix24\Exceptions\Bitrix24WrongClientException; +use Bitrix24\Exceptions\Bitrix24MethodNotFoundException; +use Bitrix24\Exceptions\Bitrix24TokenIsExpiredException; +use Bitrix24\Exceptions\Bitrix24PortalDeletedException; +use Bitrix24\Exceptions\Bitrix24SecurityException; /** * Class Bitrix24 @@ -266,22 +269,26 @@ public function getMethodParameters() { } - /** - * Execute Bitrix24 REST API method - * - * @param string $methodName - * @param array $additionalParameters - * - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24TokenIsInvalid - * @throws Bitrix24TokenIsExpired - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24SecurityException - * - * @return array - */ + /** + * Execute Bitrix24 REST API method + * + * @param string $methodName + * @param array $additionalParameters + * + * @throws Bitrix24Exception + * @throws Bitrix24ApiException + * @throws Bitrix24TokenIsInvalidException + * @throws Bitrix24TokenIsExpiredException + * @throws Bitrix24WrongClientException + * @throws Bitrix24MethodNotFoundException + * @throws Bitrix24PaymentRequiredException + * @throws Bitrix24SecurityException + * @throws Bitrix24PortalDeletedException + * @throws Bitrix24IoException + * @throws Bitrix24EmptyResponseException + * + * @return array + */ public function call($methodName, array $additionalParameters = array()) { } @@ -298,54 +305,67 @@ public function getRawResponse() { } - /** - * Get new access token - * - * @return array - * - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24TokenIsInvalid - * @throws Bitrix24TokenIsExpired - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - */ + /** + * Get new access token + * + * @return array + * + * @throws Bitrix24Exception + * @throws Bitrix24ApiException + * @throws Bitrix24PortalDeletedException + * @throws Bitrix24IoException + * @throws Bitrix24EmptyResponseException + * @throws Bitrix24TokenIsInvalidException + * @throws Bitrix24TokenIsExpiredException + * @throws Bitrix24WrongClientException + * @throws Bitrix24MethodNotFoundException + * @throws Bitrix24PaymentRequiredException + * + */ public function getNewAccessToken() { } - /** - * Authorize and get first access token - * - * @param $code - * - * @return array - * - * @throws Bitrix24ApiException - * @throws Bitrix24Exception - * @throws Bitrix24IoException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24TokenIsExpired - * @throws Bitrix24TokenIsInvalid - * @throws Bitrix24WrongClientException - */ + /** + * Authorize and get first access token + * + * @param $code + * + * @return array + * + * @throws Bitrix24Exception + * @throws Bitrix24ApiException + * @throws Bitrix24PortalDeletedException + * @throws Bitrix24IoException + * @throws Bitrix24EmptyResponseException + * @throws Bitrix24TokenIsInvalidException + * @throws Bitrix24TokenIsExpiredException + * @throws Bitrix24WrongClientException + * @throws Bitrix24MethodNotFoundException + * @throws Bitrix24PaymentRequiredException + * + */ public function getFirstAccessToken($code) { } - /** - * Check is access token expire, call list of all available api-methods from B24 portal with current access token - * if we have an error code expired_token then return true else return false - * - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24TokenIsInvalid - * @throws Bitrix24TokenIsExpired - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * - * @return boolean - */ + /** + * Check is access token expire, call list of all available api-methods from B24 portal with current access token + * if we have an error code expired_token then return true else return false + * + * @throws Bitrix24Exception + * @throws Bitrix24ApiException + * @throws Bitrix24PortalDeletedException + * @throws Bitrix24IoException + * @throws Bitrix24EmptyResponseException + * @throws Bitrix24TokenIsInvalidException + * @throws Bitrix24TokenIsExpiredException + * @throws Bitrix24WrongClientException + * @throws Bitrix24MethodNotFoundException + * @throws Bitrix24PaymentRequiredException + * + * @return boolean + */ public function isAccessTokenExpire() { } diff --git a/tests/src/Bitrix24Test.php b/tests/src/Bitrix24Test.php index af9d8d85..5b1198d2 100644 --- a/tests/src/Bitrix24Test.php +++ b/tests/src/Bitrix24Test.php @@ -7,7 +7,6 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Bitrix24; use \Psr\Log\NullLogger; @@ -23,7 +22,7 @@ class Bitrix24Test extends \PHPUnit_Framework_TestCase */ public function testConstructorWithFirstArgumentIsNotBoolean() { - $this->setExpectedException('\Bitrix24\Bitrix24Exception'); + $this->setExpectedException('\Bitrix24\Exceptions\Bitrix24Exception'); $obBitrix24 = new Bitrix24(array()); } /** @@ -54,7 +53,7 @@ public function testSetMemberIdWithValidArgument() */ public function testSetMemberIdWithNullArgument() { - $this->setExpectedException('\Bitrix24\Bitrix24Exception'); + $this->setExpectedException('\Bitrix24\Exceptions\Bitrix24Exception'); $obBitrix24 = new Bitrix24(false, new NullLogger()); $result = $obBitrix24->setMemberId(null); $this->assertTrue($result); @@ -64,7 +63,7 @@ public function testSetMemberIdWithNullArgument() */ public function testSetMemberIdWithEmptyStringArgument() { - $this->setExpectedException('\Bitrix24\Bitrix24Exception'); + $this->setExpectedException('\Bitrix24\Exceptions\Bitrix24Exception'); $obBitrix24 = new Bitrix24(false, new NullLogger()); $result = $obBitrix24->setMemberId(''); $this->assertTrue($result); @@ -74,7 +73,7 @@ public function testSetMemberIdWithEmptyStringArgument() */ public function testSetRetriesToConnectCountWithNull() { - $this->setExpectedException('\Bitrix24\Bitrix24Exception'); + $this->setExpectedException('\Bitrix24\Exceptions\Bitrix24Exception'); $obBitrix24 = new Bitrix24(false, new NullLogger()); $result = $obBitrix24->setRetriesToConnectCount(null); } @@ -101,7 +100,7 @@ public function testSetRetriesToConnectCountWithValidArgs() */ public function testSetRetriesToConnectTimeoutWithNull() { - $this->setExpectedException('\Bitrix24\Bitrix24Exception'); + $this->setExpectedException('\Bitrix24\Exceptions\Bitrix24Exception'); $obBitrix24 = new Bitrix24(false, new NullLogger()); $result = $obBitrix24->setRetriesToConnectTimeout(null); } From 04a92922e1eb0e3a3e78dd7c8a255eab545a3372 Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Fri, 5 Aug 2016 00:22:26 +0300 Subject: [PATCH 069/647] task#44 Add bitrix24 events --- src/presets/event/event.php | 295 ++++++++++++++++++++++-------------- 1 file changed, 182 insertions(+), 113 deletions(-) diff --git a/src/presets/event/event.php b/src/presets/event/event.php index 15509097..a6d10e54 100644 --- a/src/presets/event/event.php +++ b/src/presets/event/event.php @@ -1,121 +1,190 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ namespace Bitrix24\Presets\Event; + /** * Class Event * @package Bitrix24\Presets\Event */ class Event { - /** - * event code when bitrix24 application has uninstall - */ - const ON_APP_UNINSTALL = 'ONAPPUNINSTALL'; - /** - * event code when bitrix24 application update - */ - const ON_APP_UPDATE = 'ONAPPUPDATE'; - /** - * event code when bitrix24 application payment - */ - const ON_APP_PAYMENT = 'ONAPPPAYMENT'; - /** - * event code when task add in bitrix24 - */ - const ON_TASK_ADD = 'ONTASKADD'; - /** - * event code when task in bitrix24 has update - */ - const ON_TASK_UPDATE = 'ONTASKUPDATE'; - /** - * event code when task in bitrix24 has delete - */ - const ON_TASK_DELETE = 'ONTASKDELETE'; - /** - * event code when new user in bitrix24 has added - */ - const ON_USER_ADD = 'ONUSERADD'; - /** - * @var string - */ - const ON_CRM_LEAD_ADD = "ONCRMLEADADD"; - /** - * @var string - */ - const ON_CRM_LEAD_UPDATE = "ONCRMLEADUPDATE"; - /** - * @var string - */ - const ON_CRM_LEAD_DELETE = "ONCRMLEADDELETE"; - /** - * @var string - */ - const ON_CRM_DEAL_ADD = "ONCRMDEALADD"; - /** - * @var string - */ - const ON_CRM_DEAL_UPDATE = "ONCRMDEALUPDATE"; - /** - * @var string - */ - const ON_CRM_DEAL_DELETE = "ONCRMDEALDELETE"; - /** - * @var string - */ - const ON_CRM_COMPANY_ADD = "ONCRMCOMPANYADD"; - /** - * @var string - */ - const ON_CRM_COMPANY_UPDATE = "ONCRMCOMPANYUPDATE"; - /** - * @var string - */ - const ON_CRM_COMPANY_DELETE = "ONCRMCOMPANYDELETE"; - /** - * @var string - */ - const ON_CRM_CONTACT_ADD = "ONCRMCONTACTADD"; - /** - * @var string - */ - const ON_CRM_CONTACT_UPDATE = "ONCRMCONTACTUPDATE"; - /** - * @var string - */ - const ON_CRM_CONTACT_DELETE = "ONCRMCONTACTDELETE"; - /** - * @var string - */ - const ON_CRM_CURRENCY_ADD = "ONCRMCURRENCYADD"; - /** - * @var string - */ - const ON_CRM_CURRENCY_UPDATE = "ONCRMCURRENCYUPDATE"; - /** - * @var string - */ - const ON_CRM_CURRENCY_DELETE = "ONCRMCURRENCYDELETE"; - /** - * @var string - */ - const ON_CRM_PRODUCT_ADD = "ONCRMPRODUCTADD"; - /** - * @var string - */ - const ON_CRM_PRODUCT_UPDATE = "ONCRMPRODUCTUPDATE"; - /** - * @var string - */ - const ON_CRM_PRODUCT_DELETE = "ONCRMPRODUCTDELETE"; - /** - * @var string - */ - const ON_CRM_ACTIVITY_ADD = "ONCRMACTIVITYADD"; - /** - * @var string - */ - const ON_CRM_ACTIVITY_UPDATE = "ONCRMACTIVITYUPDATE"; - /** - * @var string - */ - const ON_CRM_ACTIVITY_DELETE = "ONCRMACTIVITYDELETE"; -} \ No newline at end of file + /** + * @var string event code when bitrix24 application has uninstall + */ + const ON_APP_UNINSTALL = 'ONAPPUNINSTALL'; + /** + * @var string event code when bitrix24 application install + */ + const ON_APP_INSTALL = 'ONAPPINSTALL'; + /** + * @var string event code when bitrix24 application update + */ + const ON_APP_UPDATE = 'ONAPPUPDATE'; + /** + * @var string event code when bitrix24 application payment + */ + const ON_APP_PAYMENT = 'ONAPPPAYMENT'; + /** + * @var string + */ + const ON_APP_TEST = 'ONAPPTEST'; + /** + * @var string event code when task add in bitrix24 + */ + const ON_TASK_ADD = 'ONTASKADD'; + /** + * @var string + */ + const ON_VOXIMPLANT_CALL_INIT = 'ONVOXIMPLANTCALLINIT'; + /** + * @var string + */ + const ON_VOXIMPLANT_CALL_START = 'ONVOXIMPLANTCALLSTART'; + /** + * @var string + */ + const ON_VOXIMPLANT_CALL_END = 'ONVOXIMPLANTCALLEND'; + /** + * @var string event code when task in bitrix24 has update + */ + const ON_TASK_UPDATE = 'ONTASKUPDATE'; + /** + * @var string event code when task in bitrix24 has delete + */ + const ON_TASK_DELETE = 'ONTASKDELETE'; + /** + * @var string + */ + const ON_TASK_COMMENT_ADD = 'ONTASKCOMMENTADD'; + /** + * @var string + */ + const ON_TASK_COMMENT_UPDATE = 'ONTASKCOMMENTUPDATE'; + /** + * @var string + */ + const ON_TASK_COMMENT_DELETE = 'ONTASKCOMMENTDELETE'; + /** + * @var string event code when new user in bitrix24 has added + */ + const ON_USER_ADD = 'ONUSERADD'; + /** + * @var string + */ + const ON_CRM_LEAD_ADD = 'ONCRMLEADADD'; + /** + * @var string + */ + const ON_CRM_LEAD_UPDATE = 'ONCRMLEADUPDATE'; + /** + * @var string + */ + const ON_CRM_LEAD_DELETE = 'ONCRMLEADDELETE'; + /** + * @var string + */ + const ON_CRM_DEAL_ADD = 'ONCRMDEALADD'; + /** + * @var string + */ + const ON_CRM_DEAL_UPDATE = 'ONCRMDEALUPDATE'; + /** + * @var string + */ + const ON_CRM_DEAL_DELETE = 'ONCRMDEALDELETE'; + /** + * @var string + */ + const ON_CRM_COMPANY_ADD = 'ONCRMCOMPANYADD'; + /** + * @var string + */ + const ON_CRM_COMPANY_UPDATE = 'ONCRMCOMPANYUPDATE'; + /** + * @var string + */ + const ON_CRM_COMPANY_DELETE = 'ONCRMCOMPANYDELETE'; + /** + * @var string + */ + const ON_CRM_CONTACT_ADD = 'ONCRMCONTACTADD'; + /** + * @var string + */ + const ON_CRM_CONTACT_UPDATE = 'ONCRMCONTACTUPDATE'; + /** + * @var string + */ + const ON_CRM_CONTACT_DELETE = 'ONCRMCONTACTDELETE'; + /** + * @var string + */ + const ON_CRM_CURRENCY_ADD = 'ONCRMCURRENCYADD'; + /** + * @var string + */ + const ON_CRM_CURRENCY_UPDATE = 'ONCRMCURRENCYUPDATE'; + /** + * @var string + */ + const ON_CRM_CURRENCY_DELETE = 'ONCRMCURRENCYDELETE'; + /** + * @var string + */ + const ON_CRM_PRODUCT_ADD = 'ONCRMPRODUCTADD'; + /** + * @var string + */ + const ON_CRM_PRODUCT_UPDATE = 'ONCRMPRODUCTUPDATE'; + /** + * @var string + */ + const ON_CRM_PRODUCT_DELETE = 'ONCRMPRODUCTDELETE'; + /** + * @var string + */ + const ON_CRM_ACTIVITY_ADD = 'ONCRMACTIVITYADD'; + /** + * @var string + */ + const ON_CRM_ACTIVITY_UPDATE = 'ONCRMACTIVITYUPDATE'; + /** + * @var string + */ + const ON_CRM_ACTIVITY_DELETE = 'ONCRMACTIVITYDELETE'; + /** + * @var string + */ + const ON_CRM_QUOTE_ADD = 'ONCRMQUOTEADD'; + /** + * @var string + */ + const ON_CRM_QUOTE_UPDATE = 'ONCRMQUOTEUPDATE'; + /** + * @var string + */ + const ON_CRM_QUOTE_DELETE = 'ONCRMQUOTEDELETE'; + /** + * @var string event on bot add to chat or private chat + */ + const ON_IM_BOT_JOIN_CHAT = 'ONIMBOTJOINCHAT'; + /** + * @var string event on bot delete + */ + const ON_IM_BOT_DELETE = 'ONIMBOTDELETE'; + /** + * @var string event on bot gets message + */ + const ON_IM_BOT_MESSAGE_ADD = 'ONIMBOTMESSAGEADD'; + /** + * @var string event on bot gets command + */ + const ON_IM_COMMAND_ADD = 'ONIMCOMMANDADD'; +} From 1747c3e564e73699e08112d7be327c3bc2594947 Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Fri, 5 Aug 2016 00:26:08 +0300 Subject: [PATCH 070/647] task#47 Update scope presets class --- CHANGELOG.md | 5 +++ src/bitrix24.php | 8 ++++ src/bitrix24exception.php | 87 ------------------------------------- src/presets/scope.php | 90 ++++++++++++++++++++++++++++++++++----- 4 files changed, 93 insertions(+), 97 deletions(-) delete mode 100644 src/bitrix24exception.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 56ced4a0..d77fb828 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,9 @@ # bitrix24-php-sdk change log +## 0.4.1 (4.08.2016) +* add new events in class `Bitrix24\Presets\Event\Event` see issue [Add new bitrix24 events #44](https://github.com/mesilov/bitrix24-php-sdk/issues/44) +* add new scope in class `Bitrix24\Presets\Scope` see issue [Update scope presets class #47](https://github.com/mesilov/bitrix24-php-sdk/issues/47) +* remove file with old deprecated exceptions see issue [Move all exceptions in namespace «Exceptions» #46](https://github.com/mesilov/bitrix24-php-sdk/issues/46) + ## 0.4.0 (16.07.2016) * remove all exceptions in namespace `\Exceptions` see issue [Move all exceptions in namespace «Exceptions» #46](https://github.com/mesilov/bitrix24-php-sdk/issues/46) * add class `Bitrix24\Exceptions\Bitrix24Exception` diff --git a/src/bitrix24.php b/src/bitrix24.php index 71232438..e894535d 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -1,4 +1,12 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ namespace Bitrix24; use Bitrix24\Contracts\iBitrix24; diff --git a/src/bitrix24exception.php b/src/bitrix24exception.php deleted file mode 100644 index 81292f1f..00000000 --- a/src/bitrix24exception.php +++ /dev/null @@ -1,87 +0,0 @@ - Date: Sun, 21 Aug 2016 19:48:40 +0300 Subject: [PATCH 071/647] isEventHandlerCodeValid --- src/classes/event/event.php | 68 ++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/src/classes/event/event.php b/src/classes/event/event.php index 6e4b7994..617b226d 100644 --- a/src/classes/event/event.php +++ b/src/classes/event/event.php @@ -17,40 +17,40 @@ class Event extends Bitrix24Entity */ protected function isEventHandlerCodeValid($eventHandlerName) { - $isEventHandlerCodeValid = false; - switch(strtoupper($eventHandlerName)) - { - case EventType::ON_APP_UPDATE: - case EventType::ON_APP_PAYMENT: - case EventType::ON_APP_UNINSTALL: - case EventType::ON_TASK_ADD: - case EventType::ON_TASK_DELETE: - case EventType::ON_TASK_UPDATE: - case EventType::ON_USER_ADD: - case EventType::ON_CRM_ACTIVITY_ADD: - case EventType::ON_CRM_ACTIVITY_DELETE: - case EventType::ON_CRM_ACTIVITY_UPDATE: - case EventType::ON_CRM_COMPANY_ADD: - case EventType::ON_CRM_COMPANY_DELETE: - case EventType::ON_CRM_COMPANY_UPDATE: - case EventType::ON_CRM_CONTACT_ADD: - case EventType::ON_CRM_CONTACT_DELETE: - case EventType::ON_CRM_CONTACT_UPDATE: - case EventType::ON_CRM_CURRENCY_ADD: - case EventType::ON_CRM_CURRENCY_DELETE: - case EventType::ON_CRM_CURRENCY_UPDATE: - case EventType::ON_CRM_DEAL_ADD: - case EventType::ON_CRM_DEAL_DELETE: - case EventType::ON_CRM_DEAL_UPDATE: - case EventType::ON_CRM_LEAD_ADD: - case EventType::ON_CRM_LEAD_DELETE: - case EventType::ON_CRM_LEAD_UPDATE: - case EventType::ON_CRM_PRODUCT_ADD: - case EventType::ON_CRM_PRODUCT_DELETE: - $isEventHandlerCodeValid = true; - break; - } - return $isEventHandlerCodeValid; + $isEventHandlerCodeValid = false; + switch(strtoupper($eventHandlerName)) + { + case EventType::ON_APP_UPDATE: + case EventType::ON_APP_PAYMENT: + case EventType::ON_APP_UNINSTALL: + case EventType::ON_TASK_ADD: + case EventType::ON_TASK_DELETE: + case EventType::ON_TASK_UPDATE: + case EventType::ON_USER_ADD: + case EventType::ON_CRM_ACTIVITY_ADD: + case EventType::ON_CRM_ACTIVITY_DELETE: + case EventType::ON_CRM_ACTIVITY_UPDATE: + case EventType::ON_CRM_COMPANY_ADD: + case EventType::ON_CRM_COMPANY_DELETE: + case EventType::ON_CRM_COMPANY_UPDATE: + case EventType::ON_CRM_CONTACT_ADD: + case EventType::ON_CRM_CONTACT_DELETE: + case EventType::ON_CRM_CONTACT_UPDATE: + case EventType::ON_CRM_CURRENCY_ADD: + case EventType::ON_CRM_CURRENCY_DELETE: + case EventType::ON_CRM_CURRENCY_UPDATE: + case EventType::ON_CRM_DEAL_ADD: + case EventType::ON_CRM_DEAL_DELETE: + case EventType::ON_CRM_DEAL_UPDATE: + case EventType::ON_CRM_LEAD_ADD: + case EventType::ON_CRM_LEAD_DELETE: + case EventType::ON_CRM_LEAD_UPDATE: + case EventType::ON_CRM_PRODUCT_ADD: + case EventType::ON_CRM_PRODUCT_DELETE: + $isEventHandlerCodeValid = true; + break; + } + return $isEventHandlerCodeValid; } /** From 50bd6930b6986768d5a814a54cdd379742fbb098 Mon Sep 17 00:00:00 2001 From: Deha Date: Sun, 21 Aug 2016 20:17:24 +0300 Subject: [PATCH 072/647] isEventHandlerCodeValid --- src/classes/event/event.php | 37 +++---------------------------------- 1 file changed, 3 insertions(+), 34 deletions(-) diff --git a/src/classes/event/event.php b/src/classes/event/event.php index 617b226d..18fd9bd8 100644 --- a/src/classes/event/event.php +++ b/src/classes/event/event.php @@ -17,40 +17,9 @@ class Event extends Bitrix24Entity */ protected function isEventHandlerCodeValid($eventHandlerName) { - $isEventHandlerCodeValid = false; - switch(strtoupper($eventHandlerName)) - { - case EventType::ON_APP_UPDATE: - case EventType::ON_APP_PAYMENT: - case EventType::ON_APP_UNINSTALL: - case EventType::ON_TASK_ADD: - case EventType::ON_TASK_DELETE: - case EventType::ON_TASK_UPDATE: - case EventType::ON_USER_ADD: - case EventType::ON_CRM_ACTIVITY_ADD: - case EventType::ON_CRM_ACTIVITY_DELETE: - case EventType::ON_CRM_ACTIVITY_UPDATE: - case EventType::ON_CRM_COMPANY_ADD: - case EventType::ON_CRM_COMPANY_DELETE: - case EventType::ON_CRM_COMPANY_UPDATE: - case EventType::ON_CRM_CONTACT_ADD: - case EventType::ON_CRM_CONTACT_DELETE: - case EventType::ON_CRM_CONTACT_UPDATE: - case EventType::ON_CRM_CURRENCY_ADD: - case EventType::ON_CRM_CURRENCY_DELETE: - case EventType::ON_CRM_CURRENCY_UPDATE: - case EventType::ON_CRM_DEAL_ADD: - case EventType::ON_CRM_DEAL_DELETE: - case EventType::ON_CRM_DEAL_UPDATE: - case EventType::ON_CRM_LEAD_ADD: - case EventType::ON_CRM_LEAD_DELETE: - case EventType::ON_CRM_LEAD_UPDATE: - case EventType::ON_CRM_PRODUCT_ADD: - case EventType::ON_CRM_PRODUCT_DELETE: - $isEventHandlerCodeValid = true; - break; - } - return $isEventHandlerCodeValid; + $reflection = new \ReflectionClass('\Bitrix24\Presets\Event\Event'); + $result = $reflection->getConstant(strtoupper($eventHandlerName)); + return isset($result); } /** From 296059cd2340fd70499ac912d5cb1de24cbdf86c Mon Sep 17 00:00:00 2001 From: Deha Date: Sun, 21 Aug 2016 20:35:30 +0300 Subject: [PATCH 073/647] Task#48 Add method sonet_group.user.get --- src/classes/sonetgroup.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/classes/sonetgroup.php b/src/classes/sonetgroup.php index 85ba17e8..1dd317fa 100644 --- a/src/classes/sonetgroup.php +++ b/src/classes/sonetgroup.php @@ -21,4 +21,16 @@ public function Get($ORDER, $FILTER) )); return $result; } + + /** + * @param $FILTER + * @return array + */ + public function UserGet($FILTER) + { + $result= $this->client->call('sonet_group.user.get', + $FILTER + ); + return $result; + } } \ No newline at end of file From 681516d85487ff103e80703b8f9da9db1ad6ebdf Mon Sep 17 00:00:00 2001 From: Deha Date: Sat, 27 Aug 2016 19:13:40 +0300 Subject: [PATCH 074/647] fix error in \Bitrix24\Task\ElapsedItem::add() --- src/classes/task/elapseditem.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/classes/task/elapseditem.php b/src/classes/task/elapseditem.php index 76d96e0f..9d237ff9 100644 --- a/src/classes/task/elapseditem.php +++ b/src/classes/task/elapseditem.php @@ -89,7 +89,7 @@ public function get($taskId, $elapsedItemId) */ public function add($taskId, $fields) { - $result = $this->client->call('task.elapseditem.add', array($taskId, array($fields))); + $result = $this->client->call('task.elapseditem.add', array($taskId, $fields)); return $result; } From 90bc6bbc15c763e2bb31761a4b4dfd0ed32c047f Mon Sep 17 00:00:00 2001 From: Boudewijn van Breukelen Date: Fri, 2 Sep 2016 14:38:55 +0200 Subject: [PATCH 075/647] Fixed two errors on line 879 in isAccessTokenExpire method --- src/bitrix24.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitrix24.php b/src/bitrix24.php index e894535d..5c52d3a0 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -876,7 +876,7 @@ public function isAccessTokenExpire() // $url = 'https://'.self::OAUTH_SERVER.'/rest/app.info?auth='.$accessToken; $url = 'https://' . $domain . '/rest/app.info?auth=' . $accessToken; $requestResult = $this->executeRequest($url); - if (in_array($requestResult['error'], array('expired_token', 'invalid_token', 'WRONG_TOKEN'), false)) { + if (isset($requestResult['error']) && in_array($requestResult['error'], array('EXPIRED_TOKEN', 'INVALID_TOKEN', 'WRONG_TOKEN'), false)) { $isTokenExpire = true; } else { // handle other errors @@ -1008,4 +1008,4 @@ public function getRetriesToConnectTimeout() { return $this->retriesToConnectTimeout; } -} \ No newline at end of file +} From ab2e6fa8147a8fb0875c216023c68f5f5192f174 Mon Sep 17 00:00:00 2001 From: Boudewijn van Breukelen Date: Fri, 2 Sep 2016 14:42:03 +0200 Subject: [PATCH 076/647] Added support for Quote API calls even though undocumented still --- src/classes/crm/quote/quote.php | 106 ++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 src/classes/crm/quote/quote.php diff --git a/src/classes/crm/quote/quote.php b/src/classes/crm/quote/quote.php new file mode 100644 index 00000000..2cdaa682 --- /dev/null +++ b/src/classes/crm/quote/quote.php @@ -0,0 +1,106 @@ +client->call( + 'crm.quote.list', + array( + 'order' => $order, + 'filter'=> $filter, + 'select'=> $select, + 'start' => $start + ) + ); + return $fullResult; + } + + /** + * get quote by id + * @var $quoteId integer quote identifier + * @link http://dev.1c-bitrix.ru/rest_help/crm/quote/crm_quote_get.php + * @return array + */ + public function get($quoteId) + { + $fullResult = $this->client->call( + 'crm.quote.get', + array('id' => $quoteId) + ); + return $fullResult; + } + + /** + * delete quote by id + * @var $quoteId integer quote identifier + * @link http://dev.1c-bitrix.ru/rest_help/crm/quote/crm_quote_delete.php + * @return array + */ + public function delete($quoteId) + { + $fullResult = $this->client->call( + 'crm.quote.delete', + array('id' => $quoteId) + ); + return $fullResult; + } + + /** + * Add a new quote to CRM + * @param array $fields array of fields + * @link http://dev.1c-bitrix.ru/rest_help/crm/quote/crm_quote_add.php + * @return array + */ + public function add($fields = array()) + { + $fullResult = $this->client->call( + 'crm.quote.add', + array('fields' => $fields) + ); + return $fullResult; + } + + /** + * update quote by id + * @var $quoteId integer quote identifier + * @var $quoteFields array quote fields to update + * @link http://dev.1c-bitrix.ru/rest_help/crm/quote/crm_quote_update.php + * @return array + */ + public function update($quoteId, $quoteFields) + { + $fullResult = $this->client->call( + 'crm.quote.update', + array( + 'id' => $quoteId, + 'fields' => $quoteFields + ) + ); + return $fullResult; + } + + /** + * get list of quote fields with description + * @link http://dev.1c-bitrix.ru/rest_help/crm/quote/crm_quote_fields.php + * @return array + */ + public function fields() + { + $fullResult = $this->client->call( + 'crm.quote.fields' + ); + return $fullResult; + } +} From 1261cf80fcbb80bd30113c6a5c3645199e0f35c7 Mon Sep 17 00:00:00 2001 From: Boudewijn van Breukelen Date: Fri, 2 Sep 2016 14:57:44 +0200 Subject: [PATCH 077/647] Modified fix to accept no errors --- src/bitrix24.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/bitrix24.php b/src/bitrix24.php index 5c52d3a0..9c122012 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -876,11 +876,13 @@ public function isAccessTokenExpire() // $url = 'https://'.self::OAUTH_SERVER.'/rest/app.info?auth='.$accessToken; $url = 'https://' . $domain . '/rest/app.info?auth=' . $accessToken; $requestResult = $this->executeRequest($url); - if (isset($requestResult['error']) && in_array($requestResult['error'], array('EXPIRED_TOKEN', 'INVALID_TOKEN', 'WRONG_TOKEN'), false)) { - $isTokenExpire = true; - } else { - // handle other errors - $this->handleBitrix24APILevelErrors($requestResult, 'app.info'); + if (isset($requestResult['error'])) { + if (in_array($requestResult['error'], array('EXPIRED_TOKEN', 'INVALID_TOKEN', 'WRONG_TOKEN'), false)) { + $isTokenExpire = true; + } else { + // handle other errors + $this->handleBitrix24APILevelErrors($requestResult, 'app.info'); + } } return $isTokenExpire; }// end of isTokenExpire From 1bec511360fe867a3d671cf3e99082bcf6a5af2d Mon Sep 17 00:00:00 2001 From: Boudewijn van Breukelen Date: Fri, 2 Sep 2016 16:59:08 +0200 Subject: [PATCH 078/647] Added if isset to catch no errors --- src/bitrix24.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitrix24.php b/src/bitrix24.php index 9c122012..e7e95c71 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -877,7 +877,7 @@ public function isAccessTokenExpire() $url = 'https://' . $domain . '/rest/app.info?auth=' . $accessToken; $requestResult = $this->executeRequest($url); if (isset($requestResult['error'])) { - if (in_array($requestResult['error'], array('EXPIRED_TOKEN', 'INVALID_TOKEN', 'WRONG_TOKEN'), false)) { + if (in_array($requestResult['error'], array('expired_token', 'invalid_token', 'WRONG_TOKEN'), false)) { $isTokenExpire = true; } else { // handle other errors From 812dcfd47422060d9abbecacb018011f9858f8fe Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Sun, 4 Sep 2016 01:25:49 +0300 Subject: [PATCH 079/647] task#49 add support http status 301 moved permanently --- CHANGELOG.md | 5 +++++ src/bitrix24.php | 1 + 2 files changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d77fb828..41d59da6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,9 @@ # bitrix24-php-sdk change log +## 0.5.0 (4.09.2016) +* add class `Bitrix24\CRM\Quote` see pr [Added support for Quote API calls](https://github.com/mesilov/bitrix24-php-sdk/pull/53/) +* add support http status 301 moved permanently in class `Bitrix24` see issue [301 Moved Permanently #49](https://github.com/mesilov/bitrix24-php-sdk/issues/49) +* fixed bug in class `Bitrix24` see pr [Issue in the isAccessTokenExpire method](https://github.com/mesilov/bitrix24-php-sdk/pull/54) + ## 0.4.1 (4.08.2016) * add new events in class `Bitrix24\Presets\Event\Event` see issue [Add new bitrix24 events #44](https://github.com/mesilov/bitrix24-php-sdk/issues/44) * add new scope in class `Bitrix24\Presets\Scope` see issue [Update scope presets class #47](https://github.com/mesilov/bitrix24-php-sdk/issues/47) diff --git a/src/bitrix24.php b/src/bitrix24.php index e7e95c71..84ff9501 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -500,6 +500,7 @@ protected function executeRequest($url, array $additionalParameters = array()) ); $curlOptions = array( + CURLOPT_FOLLOWLOCATION => true, CURLOPT_RETURNTRANSFER => true, CURLINFO_HEADER_OUT => true, CURLOPT_VERBOSE => true, From 5c77079002ae0f0bc9c95c37c6bba3c643395a8e Mon Sep 17 00:00:00 2001 From: Boudewijn van Breukelen Date: Tue, 6 Sep 2016 10:49:15 +0200 Subject: [PATCH 080/647] Added Exception for Bad Gateway error (502) --- src/bitrix24.php | 7 +++++++ src/exceptions/bitrix24badgatewayexception.php | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 src/exceptions/bitrix24badgatewayexception.php diff --git a/src/bitrix24.php b/src/bitrix24.php index e7e95c71..a81365e1 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -11,6 +11,7 @@ use Bitrix24\Contracts\iBitrix24; +use Bitrix24\Exceptions\Bitrix24BadGatewayException; use Bitrix24\Exceptions\Bitrix24Exception; use Bitrix24\Exceptions\Bitrix24IoException; use Bitrix24\Exceptions\Bitrix24PaymentRequiredException; @@ -555,6 +556,12 @@ protected function executeRequest($url, array $additionalParameters = array()) $this->log->error($errorMsg, $this->getErrorContext()); throw new Bitrix24PortalDeletedException($errorMsg); break; + + case 502: + $errorMsg = sprintf('bad gateway to portal [%s]', $this->getDomain()); + $this->log->error($errorMsg, $this->getErrorContext()); + throw new Bitrix24BadGatewayException($errorMsg); + break; } // handling server-side API errors: empty response from bitrix24 portal diff --git a/src/exceptions/bitrix24badgatewayexception.php b/src/exceptions/bitrix24badgatewayexception.php new file mode 100644 index 00000000..72f6c1a1 --- /dev/null +++ b/src/exceptions/bitrix24badgatewayexception.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Bitrix24\Exceptions; + +/** + * Class Bitrix24BadGatewayException + * @package Bitrix24 + */ +class Bitrix24BadGatewayException extends Bitrix24Exception +{ +} \ No newline at end of file From 6c3f32ec8f1235782e68039487b76e14373cd8b9 Mon Sep 17 00:00:00 2001 From: Boudewijn van Breukelen Date: Tue, 6 Sep 2016 11:41:26 +0200 Subject: [PATCH 081/647] Moved BadGateway Exception to IOException --- src/exceptions/bitrix24badgatewayexception.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/exceptions/bitrix24badgatewayexception.php b/src/exceptions/bitrix24badgatewayexception.php index 72f6c1a1..7094504f 100644 --- a/src/exceptions/bitrix24badgatewayexception.php +++ b/src/exceptions/bitrix24badgatewayexception.php @@ -13,6 +13,6 @@ * Class Bitrix24BadGatewayException * @package Bitrix24 */ -class Bitrix24BadGatewayException extends Bitrix24Exception +class Bitrix24BadGatewayException extends Bitrix24IoException { } \ No newline at end of file From 5de99cca1cbfad053ebf8a25b2981cfb6f94ccaa Mon Sep 17 00:00:00 2001 From: Leonid Volokitin Date: Wed, 22 Feb 2017 11:22:46 +0300 Subject: [PATCH 082/647] Added deal ProductRows class --- src/classes/crm/deal/productrows.php | 46 ++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/classes/crm/deal/productrows.php diff --git a/src/classes/crm/deal/productrows.php b/src/classes/crm/deal/productrows.php new file mode 100644 index 00000000..af35edf3 --- /dev/null +++ b/src/classes/crm/deal/productrows.php @@ -0,0 +1,46 @@ +client->call( + 'crm.deal.productrows.get', + array( + 'id' => $id + ) + ); + return $fullResult; + } + + /** + * Set deal products. + * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_productrows_set.php + * @param int $id - deal id + * @param array $rows - products data + * @return array + */ + public function set($id, $rows) + { + $fullResult = $this->client->call( + 'crm.deal.productrows.set', + array( + 'id' => $id, + 'rows' => $rows + ) + ); + return $fullResult; + } +} From 77d38cffd949977b676942db2cec4447a001bf73 Mon Sep 17 00:00:00 2001 From: Abyr Valg Date: Wed, 15 Mar 2017 17:04:01 +0300 Subject: [PATCH 083/647] support for batch calls --- src/bitrix24.php | 77 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/src/bitrix24.php b/src/bitrix24.php index 883c131a..34d83d21 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -44,6 +44,16 @@ class Bitrix24 implements iBitrix24 */ const OAUTH_SERVER = 'oauth.bitrix.info'; + /** + * Max calls in one batch + */ + const MAX_BATCH_CALLS = 50; + + /** + * Default delay between batch calls (in msec) + */ + const BATCH_DELAY = 500000; + /** * @var string access token */ @@ -130,6 +140,11 @@ class Bitrix24 implements iBitrix24 */ protected $retriesToConnectTimeout; + /** + * @var array pending batch calls + */ + protected $_batch = array(); + /** * Create a object to work with Bitrix24 REST API service * @@ -1018,4 +1033,66 @@ public function getRetriesToConnectTimeout() { return $this->retriesToConnectTimeout; } + + /** + * Add call to batch. If [[$callback]] parameter is set, it will receive call result as first parameter. + * + * @param string $method + * @param array $parameters + * @param callable|null $callback + */ + public function addBatchCall($method, array $parameters = array(), callable $callback = null) + { + $this->_batch[] = array( + 'method' => $method, + 'parameters' => $parameters, + 'callback' => $callback, + ); + } + + /** + * Return true, if we have unprocessed batch calls. + * + * @return bool + */ + public function hasBatchCalls() + { + return (bool) count($this->_batch); + } + + /** + * Process batch calls. + * + * @param int $halt Halt batch on error + * @param int $delay Delay between batch calls (in msec) + * @throws Bitrix24Exception + * @throws Bitrix24SecurityException + */ + public function processBatchCalls($halt = 0, $delay = self::BATCH_DELAY) + { + while (count($this->_batch)) { + $slice = array_splice($this->_batch, 0, self::MAX_BATCH_CALLS); + $commands = array(); + foreach ($slice as $idx => $call) { + $commands[$idx] = $call['method'] . '?' . http_build_query($call['parameters']); + } + $batchResult = $this->call('batch', array('halt' => $halt, 'cmd' => $commands)); + $results = $batchResult['result']; + foreach ($slice as $idx => $call) { + if (!isset($call['callback']) || !is_callable($call['callback'])) { + continue; + } + + call_user_func($call['callback'], array( + 'result' => isset($results['result'][$idx]) ? $results['result'][$idx] : null, + 'error' => isset($results['result_error'][$idx]) ? $results['result_error'][$idx] : null, + 'total' => isset($results['result_total'][$idx]) ? $results['result_total'][$idx] : null, + 'next' => isset($results['result_next'][$idx]) ? $results['result_next'][$idx] : null, + )); + } + if (count($this->_batch) && $delay) { + usleep($delay); + } + } + } } From 0905b192149a38db5082b316e2848231d8b576b2 Mon Sep 17 00:00:00 2001 From: Abyr Valg Date: Thu, 16 Mar 2017 19:02:54 +0300 Subject: [PATCH 084/647] use unique batch call ids --- src/bitrix24.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/bitrix24.php b/src/bitrix24.php index 34d83d21..041f2b38 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -1040,14 +1040,18 @@ public function getRetriesToConnectTimeout() * @param string $method * @param array $parameters * @param callable|null $callback + * + * @return string Unique call ID. */ public function addBatchCall($method, array $parameters = array(), callable $callback = null) { - $this->_batch[] = array( + $id = uniqid(); + $this->_batch[$id] = array( 'method' => $method, 'parameters' => $parameters, 'callback' => $callback, ); + return $id; } /** From 3a3c418cf4186031676caffeaffbce5dfcd4ae86 Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Sun, 30 Apr 2017 23:20:37 +0300 Subject: [PATCH 085/647] add product fields pesets --- CHANGELOG.md | 4 ++ src/classes/crm/product/product.php | 15 ++++++ src/presets/crm/product/fields.php | 72 +++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 src/presets/crm/product/fields.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 41d59da6..644185f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,8 @@ # bitrix24-php-sdk change log +## 0.5.1 (30.04.2017) +* add preset `Bitrix24\Presets\CRM\Products\Fields` +* add method `add` in class `Bitrix24\CRM\Product` + ## 0.5.0 (4.09.2016) * add class `Bitrix24\CRM\Quote` see pr [Added support for Quote API calls](https://github.com/mesilov/bitrix24-php-sdk/pull/53/) * add support http status 301 moved permanently in class `Bitrix24` see issue [301 Moved Permanently #49](https://github.com/mesilov/bitrix24-php-sdk/issues/49) diff --git a/src/classes/crm/product/product.php b/src/classes/crm/product/product.php index db8f2dc2..333306d5 100644 --- a/src/classes/crm/product/product.php +++ b/src/classes/crm/product/product.php @@ -43,6 +43,21 @@ public function get($productId) return $fullResult; } + /** + * add new product + * + * @link https://dev.1c-bitrix.ru/rest_help/crm/products/crm_product_add.php + * @param $arNewProduct + * @return array + */ + public function add($arNewProduct) + { + $fullResult = $this->client->call( + 'crm.product.add', + array('fields' => $arNewProduct) + ); + return $fullResult; + } } diff --git a/src/presets/crm/product/fields.php b/src/presets/crm/product/fields.php new file mode 100644 index 00000000..f02eb39d --- /dev/null +++ b/src/presets/crm/product/fields.php @@ -0,0 +1,72 @@ + Date: Thu, 11 May 2017 23:41:17 +0300 Subject: [PATCH 086/647] update presets for crm entity --- CHANGELOG.md | 8 +- src/presets/crm/contact/fields.php | 307 ++++++++++-------- src/presets/crm/deal/fields.php | 229 ++++++++------ src/presets/crm/lead/fields.php | 310 +++++++++++-------- src/presets/crm/product/ProductRowFields.php | 98 ++++++ 5 files changed, 600 insertions(+), 352 deletions(-) create mode 100644 src/presets/crm/product/ProductRowFields.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 644185f3..e80c7272 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # bitrix24-php-sdk change log +## 0.5.2 (11.05.2017) +* add preset `Bitrix24\Presets\CRM\Product\ProductRowFields` +* updated preset `Bitrix24\Presets\CRM\Contact\Fields` +* updated preset `Bitrix24\Presets\CRM\Deal\Fields` +* updated preset `Bitrix24\Presets\CRM\Lead\Fields` + ## 0.5.1 (30.04.2017) -* add preset `Bitrix24\Presets\CRM\Products\Fields` +* add preset `Bitrix24\Presets\CRM\Product\Fields` * add method `add` in class `Bitrix24\CRM\Product` ## 0.5.0 (4.09.2016) diff --git a/src/presets/crm/contact/fields.php b/src/presets/crm/contact/fields.php index 5226137a..e7504356 100644 --- a/src/presets/crm/contact/fields.php +++ b/src/presets/crm/contact/fields.php @@ -1,4 +1,5 @@ Date: Sat, 20 May 2017 13:36:53 +0300 Subject: [PATCH 087/647] add placement entity --- CHANGELOG.md | 5 ++ src/classes/placement/Placement.php | 74 +++++++++++++++++++++++++++++ src/presets/placement/Fields.php | 27 +++++++++++ src/presets/placement/Placement.php | 43 +++++++++++++++++ 4 files changed, 149 insertions(+) create mode 100644 src/classes/placement/Placement.php create mode 100644 src/presets/placement/Fields.php create mode 100644 src/presets/placement/Placement.php diff --git a/CHANGELOG.md b/CHANGELOG.md index e80c7272..cef61283 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,9 @@ # bitrix24-php-sdk change log +## 0.5.3 (20.05.2017) +* add class `Bitrix24\Placement\Placement` +* add preset `Bitrix24\Presets\Placement\Placement` with placement codes +* add preset `Bitrix24\Presets\Placement\Fields` with placement fields + ## 0.5.2 (11.05.2017) * add preset `Bitrix24\Presets\CRM\Product\ProductRowFields` * updated preset `Bitrix24\Presets\CRM\Contact\Fields` diff --git a/src/classes/placement/Placement.php b/src/classes/placement/Placement.php new file mode 100644 index 00000000..3673818a --- /dev/null +++ b/src/classes/placement/Placement.php @@ -0,0 +1,74 @@ +client->call('placement.bind', + array( + 'PLACEMENT' => $placementCode, + 'HANDLER' => $handlerUrl, + 'TITLE' => $title, + 'DESCRIPTION' => $description + )); + return $arResult; + } + + /** + * unregister placement handler + * + * @param $placementCode string + * @param $handlerUrl string + * + * @return array + */ + public function unbind($placementCode, $handlerUrl) + { + $arResult = $this->client->call('placement.unbind', + array( + 'PLACEMENT' => $placementCode, + 'HANDLER' => $handlerUrl + )); + return $arResult; + } + + /** + * Get possible placement locations + * + * @return array + */ + public function getPossibleLocations() + { + $arResult = $this->client->call('placement.list'); + return $arResult['result']; + } + + /** + * get locations with registered placements + * + * @return array + */ + public function getLocations() + { + $arResult = $this->client->call('placement.get'); + return $arResult['result']; + } +} \ No newline at end of file diff --git a/src/presets/placement/Fields.php b/src/presets/placement/Fields.php new file mode 100644 index 00000000..ec463fc7 --- /dev/null +++ b/src/presets/placement/Fields.php @@ -0,0 +1,27 @@ + Date: Sun, 4 Jun 2017 20:37:52 +0300 Subject: [PATCH 088/647] Callback for expired token. Fix pullrequest#63 by valga --- src/bitrix24.php | 95 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 70 insertions(+), 25 deletions(-) diff --git a/src/bitrix24.php b/src/bitrix24.php index 041f2b38..83bf7d23 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -10,22 +10,20 @@ namespace Bitrix24; use Bitrix24\Contracts\iBitrix24; - +use Bitrix24\Exceptions\Bitrix24ApiException; use Bitrix24\Exceptions\Bitrix24BadGatewayException; +use Bitrix24\Exceptions\Bitrix24EmptyResponseException; use Bitrix24\Exceptions\Bitrix24Exception; use Bitrix24\Exceptions\Bitrix24IoException; -use Bitrix24\Exceptions\Bitrix24PaymentRequiredException; -use Bitrix24\Exceptions\Bitrix24EmptyResponseException; -use Bitrix24\Exceptions\Bitrix24ApiException; -use Bitrix24\Exceptions\Bitrix24TokenIsInvalidException; -use Bitrix24\Exceptions\Bitrix24WrongClientException; use Bitrix24\Exceptions\Bitrix24MethodNotFoundException; -use Bitrix24\Exceptions\Bitrix24TokenIsExpiredException; +use Bitrix24\Exceptions\Bitrix24PaymentRequiredException; use Bitrix24\Exceptions\Bitrix24PortalDeletedException; use Bitrix24\Exceptions\Bitrix24SecurityException; - -use Psr\Log\NullLogger; +use Bitrix24\Exceptions\Bitrix24TokenIsExpiredException; +use Bitrix24\Exceptions\Bitrix24TokenIsInvalidException; +use Bitrix24\Exceptions\Bitrix24WrongClientException; use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; /** * Class Bitrix24 @@ -145,6 +143,22 @@ class Bitrix24 implements iBitrix24 */ protected $_batch = array(); + /** + * @var callable callback for expired tokens + */ + protected $_onExpiredToken; + + /** + * Set function called on token expiration. Callback receives instance as first parameter. + * If callback returns true, API call will be retried. + * + * @param callable $callback + */ + public function setOnExpiredToken(callable $callback) + { + $this->_onExpiredToken = $callback; + } + /** * Create a object to work with Bitrix24 REST API service * @@ -494,7 +508,7 @@ protected function getErrorContext() * Execute a request API to Bitrix24 using cURL * * @param string $url - * @param array $additionalParameters + * @param array $additionalParameters * * @throws Bitrix24Exception * @throws Bitrix24PortalDeletedException @@ -502,6 +516,7 @@ protected function getErrorContext() * @throws Bitrix24EmptyResponseException * * @return array + * @throws \Bitrix24\Exceptions\Bitrix24BadGatewayException */ protected function executeRequest($url, array $additionalParameters = array()) { @@ -572,7 +587,7 @@ protected function executeRequest($url, array $additionalParameters = array()) $this->log->error($errorMsg, $this->getErrorContext()); throw new Bitrix24PortalDeletedException($errorMsg); break; - + case 502: $errorMsg = sprintf('bad gateway to portal [%s]', $this->getDomain()); $this->log->error($errorMsg, $this->getErrorContext()); @@ -602,6 +617,45 @@ protected function executeRequest($url, array $additionalParameters = array()) return $jsonResult; } + + /** + * Execute Bitrix24 REST API method + * + * @param string $methodName + * @param array $additionalParameters + * + * @return mixed + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws Bitrix24TokenIsExpiredException + */ + public function call($methodName, array $additionalParameters = array()) + { + try { + $result = $this->_call($methodName, $additionalParameters); + } catch (Bitrix24TokenIsExpiredException $e) { + if (!is_callable($this->_onExpiredToken)) { + throw $e; + } + + $retry = call_user_func($this->_onExpiredToken, $this); + if (!$retry) { + throw $e; + } + $result = $this->_call($methodName, $additionalParameters); + } + + return $result; + } + /** * Execute Bitrix24 REST API method * @@ -622,13 +676,8 @@ protected function executeRequest($url, array $additionalParameters = array()) * * @return array */ - public function call($methodName, array $additionalParameters = array()) + protected function _call($methodName, array $additionalParameters = array()) { -// $arAuthServerMethods = array( -// 'app.info', -// 'app.stat' -// ); - if (null === $this->getDomain()) { throw new Bitrix24Exception('domain not found, you must call setDomain method before'); } @@ -639,14 +688,7 @@ public function call($methodName, array $additionalParameters = array()) throw new Bitrix24Exception('method name not found, you must set method name'); } -// if(in_array(strtolower($methodName), $arAuthServerMethods, true)) -// { -// $url = 'https://'.self::OAUTH_SERVER.'/rest/'.$methodName; -// } -// else -// { $url = 'https://' . $this->domain . '/rest/' . $methodName; -// } $additionalParameters['auth'] = $this->accessToken; // save method parameters for debug $this->methodParameters = $additionalParameters; @@ -1067,10 +1109,13 @@ public function hasBatchCalls() /** * Process batch calls. * - * @param int $halt Halt batch on error + * @param int $halt Halt batch on error * @param int $delay Delay between batch calls (in msec) + * * @throws Bitrix24Exception * @throws Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException */ public function processBatchCalls($halt = 0, $delay = self::BATCH_DELAY) { From ffa39ef0b8c3b2e13b4c9bbb681833f47fe4cb45 Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Mon, 5 Jun 2017 11:53:42 +0300 Subject: [PATCH 089/647] add mthod update to entity Products --- src/classes/crm/product/product.php | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/classes/crm/product/product.php b/src/classes/crm/product/product.php index 333306d5..1563def8 100644 --- a/src/classes/crm/product/product.php +++ b/src/classes/crm/product/product.php @@ -1,5 +1,7 @@ $order, - 'filter'=> $filter, - 'select'=> $select, - 'start' => $start + 'filter' => $filter, + 'select' => $select, + 'start' => $start ) ); return $fullResult; @@ -43,6 +45,19 @@ public function get($productId) return $fullResult; } + /** + * @param $productId + * @param array $arFields + * @return array + */ + public function update($productId, array $arFields) + { + return $this->client->call('crm.product.update', array( + 'id' => $productId, + 'fields' => $arFields + )); + } + /** * add new product * From 06087cb2126a1362fa0a16792d0464f2f08cb5d9 Mon Sep 17 00:00:00 2001 From: camaxtly Date: Mon, 12 Jun 2017 17:29:09 +0300 Subject: [PATCH 090/647] increased curl time out --- src/bitrix24.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitrix24.php b/src/bitrix24.php index 83bf7d23..eb0da1f7 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -535,8 +535,8 @@ protected function executeRequest($url, array $additionalParameters = array()) CURLOPT_RETURNTRANSFER => true, CURLINFO_HEADER_OUT => true, CURLOPT_VERBOSE => true, - CURLOPT_CONNECTTIMEOUT => 5, - CURLOPT_TIMEOUT => 5, + CURLOPT_CONNECTTIMEOUT => 65, + CURLOPT_TIMEOUT => 70, CURLOPT_USERAGENT => strtolower(__CLASS__ . '-PHP-SDK/v' . self::VERSION), CURLOPT_POST => true, CURLOPT_POSTFIELDS => http_build_query($additionalParameters), From e5e4ed743284895de9e1030a0cc73413c6ac19b6 Mon Sep 17 00:00:00 2001 From: Dekhand Alexandr Date: Tue, 27 Jun 2017 11:32:22 +0300 Subject: [PATCH 091/647] Scope placement --- src/presets/scope.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/presets/scope.php b/src/presets/scope.php index 02911c7e..3cbb4b1e 100644 --- a/src/presets/scope.php +++ b/src/presets/scope.php @@ -7,6 +7,7 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ + namespace Bitrix24\Presets; /** @@ -94,4 +95,9 @@ class Scope * @var string work with lists */ const LISTS = 'lists'; + + /** + * @var string work with placement + */ + const PLACEMENT = 'placement'; } \ No newline at end of file From 30f151a39141bb9b399c2361783308b1605628e6 Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Sat, 8 Jul 2017 15:21:39 +0300 Subject: [PATCH 092/647] task#66 add batch calls method to bitrix24 api client interface --- src/bitrix24.php | 837 +++++++++++++++++----------------- src/classes/crm/deal/deal.php | 192 ++++---- src/contracts/ibitrix24.php | 452 +++++++++--------- 3 files changed, 765 insertions(+), 716 deletions(-) diff --git a/src/bitrix24.php b/src/bitrix24.php index eb0da1f7..ce39a6ae 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -7,6 +7,7 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ + namespace Bitrix24; use Bitrix24\Contracts\iBitrix24; @@ -42,15 +43,6 @@ class Bitrix24 implements iBitrix24 */ const OAUTH_SERVER = 'oauth.bitrix.info'; - /** - * Max calls in one batch - */ - const MAX_BATCH_CALLS = 50; - - /** - * Default delay between batch calls (in msec) - */ - const BATCH_DELAY = 500000; /** * @var string access token @@ -148,17 +140,6 @@ class Bitrix24 implements iBitrix24 */ protected $_onExpiredToken; - /** - * Set function called on token expiration. Callback receives instance as first parameter. - * If callback returns true, API call will be retried. - * - * @param callable $callback - */ - public function setOnExpiredToken(callable $callback) - { - $this->_onExpiredToken = $callback; - } - /** * Create a object to work with Bitrix24 REST API service * @@ -194,6 +175,17 @@ public function __construct($isSaveRawResponse = false, LoggerInterface $obLogge $this->setRetriesToConnectTimeout(1000000); } + /** + * Set function called on token expiration. Callback receives instance as first parameter. + * If callback returns true, API call will be retried. + * + * @param callable $callback + */ + public function setOnExpiredToken(callable $callback) + { + $this->_onExpiredToken = $callback; + } + /** * Get a random string to sign protected api-call. Use salt for argument "state" in secure api-call * random string is a result of mt_rand function @@ -206,106 +198,134 @@ public function getSecuritySignSalt() } /** - * Set member ID — portal GUID + * Set custom cURL options, overriding default ones * - * @param string $memberId + * @link http://php.net/manual/en/function.curl-setopt.php * - * @throws Bitrix24Exception + * @param array $options - array(CURLOPT_XXX => value1, CURLOPT_XXX2 => value2,...) * - * @return true + * @return bool */ - public function setMemberId($memberId) + public function setCustomCurlOptions($options) { - if ('' === $memberId) { - throw new Bitrix24Exception('memberId is empty'); - } elseif (null === $memberId) { - throw new Bitrix24Exception('memberId is null'); - } - $this->memberId = $memberId; + $this->customCurlOptions = $options; + return true; } /** - * Get memeber ID + * Return additional parameters of last api-call. Data available after you try to call method call * - * @return string | null + * @return array | null */ - public function getMemberId() + public function getMethodParameters() { - return $this->memberId; + return $this->methodParameters; } /** - * Set redirect URI + * Get new access token * - * @param string $redirectUri + * @return array * * @throws Bitrix24Exception + * @throws Bitrix24ApiException + * @throws Bitrix24PortalDeletedException + * @throws Bitrix24IoException + * @throws Bitrix24EmptyResponseException + * @throws Bitrix24TokenIsInvalidException + * @throws Bitrix24TokenIsExpiredException + * @throws Bitrix24WrongClientException + * @throws Bitrix24MethodNotFoundException + * @throws Bitrix24PaymentRequiredException * - * @return true; */ - public function setRedirectUri($redirectUri) + public function getNewAccessToken() { - if ('' === $redirectUri) { - throw new Bitrix24Exception('redirect URI is empty'); + $applicationId = $this->getApplicationId(); + $applicationSecret = $this->getApplicationSecret(); + $refreshToken = $this->getRefreshToken(); + $applicationScope = $this->getApplicationScope(); + $redirectUri = $this->getRedirectUri(); + + if (null === $applicationId) { + throw new Bitrix24Exception('application id not found, you must call setApplicationId method before'); + } elseif (null === $applicationSecret) { + throw new Bitrix24Exception('application id not found, you must call setApplicationSecret method before'); + } elseif (null === $refreshToken) { + throw new Bitrix24Exception('application id not found, you must call setRefreshToken method before'); + } elseif (0 === count($applicationScope)) { + throw new Bitrix24Exception('application scope not found, you must call setApplicationScope method before'); + } elseif (null === $redirectUri) { + throw new Bitrix24Exception('application redirect URI not found, you must call setRedirectUri method before'); } - $this->redirectUri = $redirectUri; - return true; + +// $url = 'https://'.self::OAUTH_SERVER.'/oauth/token/'. + $url = 'https://' . $this->getDomain() . '/oauth/token/' . + '?client_id=' . urlencode($applicationId) . + '&grant_type=refresh_token' . + '&client_secret=' . $applicationSecret . + '&refresh_token=' . $refreshToken . + '&redirect_uri=' . urlencode($redirectUri); + $requestResult = $this->executeRequest($url); + // handling bitrix24 api-level errors + $this->handleBitrix24APILevelErrors($requestResult, 'refresh access token'); + return $requestResult; } /** - * Get redirect URI + * Get application id * - * @return string | null + * @return string */ - public function getRedirectUri() + public function getApplicationId() { - return $this->redirectUri; + return $this->applicationId; } /** - * Set access token + * Set application id * - * @param string $accessToken + * @param string $applicationId * * @throws Bitrix24Exception * - * @return true + * @return true; */ - public function setAccessToken($accessToken) + public function setApplicationId($applicationId) { - if ('' === $accessToken) { - throw new Bitrix24Exception('access token is empty'); + if ('' === $applicationId) { + throw new Bitrix24Exception('application id is empty'); } - $this->accessToken = $accessToken; + $this->applicationId = $applicationId; return true; } /** - * Get access token + * Get application secret * - * @return string | null + * @return string */ - public function getAccessToken() + public function getApplicationSecret() { - return $this->accessToken; + return $this->applicationSecret; } /** - * Set refresh token + * Set application secret * - * @param $refreshToken + * @param string $applicationSecret * * @throws Bitrix24Exception * * @return true; */ - public function setRefreshToken($refreshToken) + public function setApplicationSecret($applicationSecret) { - if ('' === $refreshToken) { - throw new Bitrix24Exception('refresh token is empty'); + if ('' === $applicationSecret) { + throw new Bitrix24Exception('application secret is empty'); } - $this->refreshToken = $refreshToken; + $this->applicationSecret = $applicationSecret; return true; } @@ -320,31 +340,31 @@ public function getRefreshToken() } /** - * Set domain + * Set refresh token * - * @param $domain + * @param $refreshToken * * @throws Bitrix24Exception * * @return true; */ - public function setDomain($domain) + public function setRefreshToken($refreshToken) { - if ('' === $domain) { - throw new Bitrix24Exception('domain is empty'); + if ('' === $refreshToken) { + throw new Bitrix24Exception('refresh token is empty'); } - $this->domain = $domain; + $this->refreshToken = $refreshToken; return true; } /** - * Get domain + * Get application scope * - * @return string | null + * @return string */ - public function getDomain() + public function getApplicationScope() { - return $this->domain; + return $this->applicationScope; } /** @@ -367,181 +387,99 @@ public function setApplicationScope(array $applicationScope) } /** - * Get application scope + * Get redirect URI * - * @return string + * @return string | null */ - public function getApplicationScope() + public function getRedirectUri() { - return $this->applicationScope; + return $this->redirectUri; } /** - * Set application id + * Set redirect URI * - * @param string $applicationId + * @param string $redirectUri * * @throws Bitrix24Exception * * @return true; */ - public function setApplicationId($applicationId) + public function setRedirectUri($redirectUri) { - if ('' === $applicationId) { - throw new Bitrix24Exception('application id is empty'); + if ('' === $redirectUri) { + throw new Bitrix24Exception('redirect URI is empty'); } - $this->applicationId = $applicationId; + $this->redirectUri = $redirectUri; return true; }// end of SetApplicationId /** - * Get application id + * Get domain * - * @return string + * @return string | null */ - public function getApplicationId() + public function getDomain() { - return $this->applicationId; + return $this->domain; } /** - * Set application secret + * Set domain * - * @param string $applicationSecret + * @param $domain * * @throws Bitrix24Exception * * @return true; */ - public function setApplicationSecret($applicationSecret) + public function setDomain($domain) { - if ('' === $applicationSecret) { - throw new Bitrix24Exception('application secret is empty'); + if ('' === $domain) { + throw new Bitrix24Exception('domain is empty'); } - $this->applicationSecret = $applicationSecret; + $this->domain = $domain; return true; } /** - * Get application secret - * - * @return string - */ - public function getApplicationSecret() - { - return $this->applicationSecret; - } - - /** - * Set custom cURL options, overriding default ones + * Execute a request API to Bitrix24 using cURL * - * @link http://php.net/manual/en/function.curl-setopt.php + * @param string $url + * @param array $additionalParameters * - * @param array $options - array(CURLOPT_XXX => value1, CURLOPT_XXX2 => value2,...) + * @throws Bitrix24Exception + * @throws Bitrix24PortalDeletedException + * @throws Bitrix24IoException + * @throws Bitrix24EmptyResponseException * - * @return bool + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24BadGatewayException */ - public function setCustomCurlOptions($options) + protected function executeRequest($url, array $additionalParameters = array()) { - $this->customCurlOptions = $options; + $retryableErrorCodes = array( + CURLE_COULDNT_RESOLVE_HOST, + CURLE_COULDNT_CONNECT, + CURLE_HTTP_NOT_FOUND, + CURLE_READ_ERROR, + CURLE_OPERATION_TIMEOUTED, + CURLE_HTTP_POST_ERROR, + CURLE_SSL_CONNECT_ERROR + ); - return true; - } - - /** - * Return raw request, contain all cURL options array and API query. Data available after you try to call method call - * numbers of array keys is const of cURL module. Example: CURLOPT_RETURNTRANSFER = 19913 - * - * @return array | null - */ - public function getRawRequest() - { - return $this->rawRequest; - } - - /** - * Return result from function curl_getinfo. Data available after you try to call method call - * - * @return array | null - */ - public function getRequestInfo() - { - return $this->requestInfo; - } - - /** - * Return additional parameters of last api-call. Data available after you try to call method call - * - * @return array | null - */ - public function getMethodParameters() - { - return $this->methodParameters; - } - - /** - * get error context - * - * @return array - */ - protected function getErrorContext() - { - return array( - // portal specific settings - 'B24_DOMAIN' => $this->getDomain(), - 'B24_MEMBER_ID' => $this->getMemberId(), - 'B24_ACCESS_TOKEN' => $this->getAccessToken(), - 'B24_REFRESH_TOKEN' => $this->getRefreshToken(), - // application settings - 'APPLICATION_SCOPE' => $this->getApplicationScope(), - 'APPLICATION_ID' => $this->getApplicationId(), - 'APPLICATION_SECRET' => $this->getApplicationSecret(), - 'REDIRECT_URI' => $this->getRedirectUri(), - // network - 'RAW_REQUEST' => $this->getRawRequest(), - 'CURL_REQUEST_INFO' => $this->getRequestInfo(), - 'RAW_RESPONSE' => $this->getRawResponse() - ); - } - - /** - * Execute a request API to Bitrix24 using cURL - * - * @param string $url - * @param array $additionalParameters - * - * @throws Bitrix24Exception - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24BadGatewayException - */ - protected function executeRequest($url, array $additionalParameters = array()) - { - $retryableErrorCodes = array( - CURLE_COULDNT_RESOLVE_HOST, - CURLE_COULDNT_CONNECT, - CURLE_HTTP_NOT_FOUND, - CURLE_READ_ERROR, - CURLE_OPERATION_TIMEOUTED, - CURLE_HTTP_POST_ERROR, - CURLE_SSL_CONNECT_ERROR - ); - - $curlOptions = array( - CURLOPT_FOLLOWLOCATION => true, - CURLOPT_RETURNTRANSFER => true, - CURLINFO_HEADER_OUT => true, - CURLOPT_VERBOSE => true, - CURLOPT_CONNECTTIMEOUT => 65, - CURLOPT_TIMEOUT => 70, - CURLOPT_USERAGENT => strtolower(__CLASS__ . '-PHP-SDK/v' . self::VERSION), - CURLOPT_POST => true, - CURLOPT_POSTFIELDS => http_build_query($additionalParameters), - CURLOPT_URL => $url - ); + $curlOptions = array( + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_RETURNTRANSFER => true, + CURLINFO_HEADER_OUT => true, + CURLOPT_VERBOSE => true, + CURLOPT_CONNECTTIMEOUT => 65, + CURLOPT_TIMEOUT => 70, + CURLOPT_USERAGENT => strtolower(__CLASS__ . '-PHP-SDK/v' . self::VERSION), + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => http_build_query($additionalParameters), + CURLOPT_URL => $url + ); if (is_array($this->customCurlOptions)) { foreach ($this->customCurlOptions as $customCurlOptionKey => $customCurlOptionValue) { @@ -617,137 +555,145 @@ protected function executeRequest($url, array $additionalParameters = array()) return $jsonResult; } - /** - * Execute Bitrix24 REST API method + * get error context * - * @param string $methodName - * @param array $additionalParameters + * @return array + */ + protected function getErrorContext() + { + return array( + // portal specific settings + 'B24_DOMAIN' => $this->getDomain(), + 'B24_MEMBER_ID' => $this->getMemberId(), + 'B24_ACCESS_TOKEN' => $this->getAccessToken(), + 'B24_REFRESH_TOKEN' => $this->getRefreshToken(), + // application settings + 'APPLICATION_SCOPE' => $this->getApplicationScope(), + 'APPLICATION_ID' => $this->getApplicationId(), + 'APPLICATION_SECRET' => $this->getApplicationSecret(), + 'REDIRECT_URI' => $this->getRedirectUri(), + // network + 'RAW_REQUEST' => $this->getRawRequest(), + 'CURL_REQUEST_INFO' => $this->getRequestInfo(), + 'RAW_RESPONSE' => $this->getRawResponse() + ); + } + + /** + * Get memeber ID * - * @return mixed - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws Bitrix24TokenIsExpiredException + * @return string | null */ - public function call($methodName, array $additionalParameters = array()) + public function getMemberId() { - try { - $result = $this->_call($methodName, $additionalParameters); - } catch (Bitrix24TokenIsExpiredException $e) { - if (!is_callable($this->_onExpiredToken)) { - throw $e; - } + return $this->memberId; + } - $retry = call_user_func($this->_onExpiredToken, $this); - if (!$retry) { - throw $e; - } - $result = $this->_call($methodName, $additionalParameters); + /** + * Set member ID — portal GUID + * + * @param string $memberId + * + * @throws Bitrix24Exception + * + * @return true + */ + public function setMemberId($memberId) + { + if ('' === $memberId) { + throw new Bitrix24Exception('memberId is empty'); + } elseif (null === $memberId) { + throw new Bitrix24Exception('memberId is null'); } + $this->memberId = $memberId; + return true; + } - return $result; + /** + * Get access token + * + * @return string | null + */ + public function getAccessToken() + { + return $this->accessToken; } /** - * Execute Bitrix24 REST API method + * Set access token * - * @param string $methodName - * @param array $additionalParameters + * @param string $accessToken * * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24TokenIsInvalidException - * @throws Bitrix24TokenIsExpiredException - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24PaymentRequiredException - * @throws Bitrix24SecurityException - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException * - * @return array + * @return true */ - protected function _call($methodName, array $additionalParameters = array()) + public function setAccessToken($accessToken) { - if (null === $this->getDomain()) { - throw new Bitrix24Exception('domain not found, you must call setDomain method before'); - } - if (null === $this->getAccessToken()) { - throw new Bitrix24Exception('access token not found, you must call setAccessToken method before'); - } - if ('' === $methodName) { - throw new Bitrix24Exception('method name not found, you must set method name'); + if ('' === $accessToken) { + throw new Bitrix24Exception('access token is empty'); } + $this->accessToken = $accessToken; + return true; + } - $url = 'https://' . $this->domain . '/rest/' . $methodName; - $additionalParameters['auth'] = $this->accessToken; - // save method parameters for debug - $this->methodParameters = $additionalParameters; - // is secure api-call? - $isSecureCall = false; - if (array_key_exists('state', $additionalParameters)) { - $isSecureCall = true; - } - // execute request - $this->log->info('call bitrix24 method', array( - 'BITRIX24_DOMAIN' => $this->domain, - 'METHOD_NAME' => $methodName, - 'METHOD_PARAMETERS' => $additionalParameters - )); - $requestResult = $this->executeRequest($url, $additionalParameters); - // check errors and throw exception if errors exists - $this->handleBitrix24APILevelErrors($requestResult, $methodName, $additionalParameters); - // handling security sign for secure api-call - if ($isSecureCall) { - if (array_key_exists('signature', $requestResult)) { - // check signature structure - if (strpos($requestResult['signature'], '.') === false) { - throw new Bitrix24SecurityException('security signature is corrupted'); - } - if (null === $this->getMemberId()) { - throw new Bitrix24Exception('member-id not found, you must call setMemberId method before'); - } - if (null === $this->getApplicationSecret()) { - throw new Bitrix24Exception('application secret not found, you must call setApplicationSecret method before'); - } - // prepare - $key = md5($this->getMemberId() . $this->getApplicationSecret()); - $delimiterPosition = strrpos($requestResult['signature'], '.'); - $dataToDecode = substr($requestResult['signature'], 0, $delimiterPosition); - $signature = base64_decode(substr($requestResult['signature'], $delimiterPosition + 1)); - // compare signatures - $hash = hash_hmac('sha256', $dataToDecode, $key, true); - if ($hash !== $signature) { - throw new Bitrix24SecurityException('security signatures not same, bad request'); - } - // decode - $arClearData = json_decode(base64_decode($dataToDecode), true); - // handling json_decode errors - $jsonErrorCode = json_last_error(); - if (null === $arClearData && (JSON_ERROR_NONE !== $jsonErrorCode)) { - /** - * @todo add function json_last_error_msg() - */ - $errorMsg = 'fatal error in function json_decode.' . PHP_EOL . 'Error code: ' . $jsonErrorCode . PHP_EOL; - throw new Bitrix24Exception($errorMsg); - } - // merge dirty and clear data - unset($arClearData['state']); - $requestResult ['result'] = array_merge($requestResult ['result'], $arClearData); - } else { - throw new Bitrix24SecurityException('security signature in api-response not found'); - } + /** + * Return raw request, contain all cURL options array and API query. Data available after you try to call method call + * numbers of array keys is const of cURL module. Example: CURLOPT_RETURNTRANSFER = 19913 + * + * @return array | null + */ + public function getRawRequest() + { + return $this->rawRequest; + } + + /** + * Return result from function curl_getinfo. Data available after you try to call method call + * + * @return array | null + */ + public function getRequestInfo() + { + return $this->requestInfo; + } + + /** + * Get raw response from Bitrix24 before json_decode call, method available only in debug mode. + * To activate debug mode you must before set to true flag isSaveRawResponse in class construct + * + * @return string | null + */ + public function getRawResponse() + { + return $this->rawResponse; + } + + /** + * get retries to connect timeout in microseconds + * + * @return mixed + */ + public function getRetriesToConnectTimeout() + { + return $this->retriesToConnectTimeout; + } + + /** + * set retries to connect timeout in microseconds + * @param int $microseconds + * @return bool + * @throws Bitrix24Exception + */ + public function setRetriesToConnectTimeout($microseconds = 1000000) + { + $this->log->debug(sprintf('set retries to connect count %s', $microseconds)); + if (!is_numeric($microseconds)) { + throw new Bitrix24Exception('retries to connect count must be an integer'); } - return $requestResult; + $this->retriesToConnectTimeout = $microseconds; + return true; } /** @@ -770,7 +716,8 @@ protected function handleBitrix24APILevelErrors( $arRequestResult, $methodName, array $additionalParameters = array() - ) { + ) + { if (array_key_exists('error', $arRequestResult)) { $errorMsg = sprintf('%s - %s in call [%s] for domain [%s]', $arRequestResult['error'], @@ -799,67 +746,6 @@ protected function handleBitrix24APILevelErrors( return null; } - /** - * Get raw response from Bitrix24 before json_decode call, method available only in debug mode. - * To activate debug mode you must before set to true flag isSaveRawResponse in class construct - * - * @return string | null - */ - public function getRawResponse() - { - return $this->rawResponse; - } - - /** - * Get new access token - * - * @return array - * - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * @throws Bitrix24TokenIsInvalidException - * @throws Bitrix24TokenIsExpiredException - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24PaymentRequiredException - * - */ - public function getNewAccessToken() - { - $applicationId = $this->getApplicationId(); - $applicationSecret = $this->getApplicationSecret(); - $refreshToken = $this->getRefreshToken(); - $applicationScope = $this->getApplicationScope(); - $redirectUri = $this->getRedirectUri(); - - if (null === $applicationId) { - throw new Bitrix24Exception('application id not found, you must call setApplicationId method before'); - } elseif (null === $applicationSecret) { - throw new Bitrix24Exception('application id not found, you must call setApplicationSecret method before'); - } elseif (null === $refreshToken) { - throw new Bitrix24Exception('application id not found, you must call setRefreshToken method before'); - } elseif (0 === count($applicationScope)) { - throw new Bitrix24Exception('application scope not found, you must call setApplicationScope method before'); - } elseif (null === $redirectUri) { - throw new Bitrix24Exception('application redirect URI not found, you must call setRedirectUri method before'); - } - -// $url = 'https://'.self::OAUTH_SERVER.'/oauth/token/'. - $url = 'https://' . $this->getDomain() . '/oauth/token/' . - '?client_id=' . urlencode($applicationId) . - '&grant_type=refresh_token' . - '&client_secret=' . $applicationSecret . - '&refresh_token=' . $refreshToken . - '&redirect_uri=' . urlencode($redirectUri); - $requestResult = $this->executeRequest($url); - // handling bitrix24 api-level errors - $this->handleBitrix24APILevelErrors($requestResult, 'refresh access token'); - return $requestResult; - } - /** * Authorize and get first access token * @@ -1022,6 +908,16 @@ public function getScope($isFull = false) return $this->executeRequest($url); } + /** + * get CURL request count retries + * + * @return int + */ + public function getRetriesToConnectCount() + { + return $this->retriesToConnectCount; + } + /** * set CURL request count retries * @param $retriesCnt @@ -1040,42 +936,6 @@ public function setRetriesToConnectCount($retriesCnt = 1) return true; } - /** - * set retries to connect timeout in microseconds - * @param int $microseconds - * @return bool - * @throws Bitrix24Exception - */ - public function setRetriesToConnectTimeout($microseconds = 1000000) - { - $this->log->debug(sprintf('set retries to connect count %s', $microseconds)); - if (!is_numeric($microseconds)) { - throw new Bitrix24Exception('retries to connect count must be an integer'); - } - $this->retriesToConnectTimeout = $microseconds; - return true; - } - - /** - * get CURL request count retries - * - * @return int - */ - public function getRetriesToConnectCount() - { - return $this->retriesToConnectCount; - } - - /** - * get retries to connect timeout in microseconds - * - * @return mixed - */ - public function getRetriesToConnectTimeout() - { - return $this->retriesToConnectTimeout; - } - /** * Add call to batch. If [[$callback]] parameter is set, it will receive call result as first parameter. * @@ -1103,13 +963,13 @@ public function addBatchCall($method, array $parameters = array(), callable $cal */ public function hasBatchCalls() { - return (bool) count($this->_batch); + return (bool)count($this->_batch); } /** * Process batch calls. * - * @param int $halt Halt batch on error + * @param int $halt Halt batch on error * @param int $delay Delay between batch calls (in msec) * * @throws Bitrix24Exception @@ -1119,12 +979,20 @@ public function hasBatchCalls() */ public function processBatchCalls($halt = 0, $delay = self::BATCH_DELAY) { + $this->log->info('Bitrix24PhpSdk.processBatchCalls.start', array('batch_query_delay' => $delay)); + $batchQueryCounter = 0; while (count($this->_batch)) { + $batchQueryCounter++; $slice = array_splice($this->_batch, 0, self::MAX_BATCH_CALLS); + $this->log->info('bitrix24PhpSdk.processBatchCalls.callItem', array( + 'batch_query_number' => $batchQueryCounter + )); + $commands = array(); foreach ($slice as $idx => $call) { $commands[$idx] = $call['method'] . '?' . http_build_query($call['parameters']); } + $batchResult = $this->call('batch', array('halt' => $halt, 'cmd' => $commands)); $results = $batchResult['result']; foreach ($slice as $idx => $call) { @@ -1143,5 +1011,138 @@ public function processBatchCalls($halt = 0, $delay = self::BATCH_DELAY) usleep($delay); } } + $this->log->info('bitrix24PhpSdk.processBatchCalls.finish'); + } + + /** + * Execute Bitrix24 REST API method + * + * @param string $methodName + * @param array $additionalParameters + * + * @return mixed + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws Bitrix24TokenIsExpiredException + */ + public function call($methodName, array $additionalParameters = array()) + { + try { + $result = $this->_call($methodName, $additionalParameters); + } catch (Bitrix24TokenIsExpiredException $e) { + if (!is_callable($this->_onExpiredToken)) { + throw $e; + } + + $retry = call_user_func($this->_onExpiredToken, $this); + if (!$retry) { + throw $e; + } + $result = $this->_call($methodName, $additionalParameters); + } + + return $result; + } + + /** + * Execute Bitrix24 REST API method + * + * @param string $methodName + * @param array $additionalParameters + * + * @throws Bitrix24Exception + * @throws Bitrix24ApiException + * @throws Bitrix24TokenIsInvalidException + * @throws Bitrix24TokenIsExpiredException + * @throws Bitrix24WrongClientException + * @throws Bitrix24MethodNotFoundException + * @throws Bitrix24PaymentRequiredException + * @throws Bitrix24SecurityException + * @throws Bitrix24PortalDeletedException + * @throws Bitrix24IoException + * @throws Bitrix24EmptyResponseException + * + * @return array + */ + protected function _call($methodName, array $additionalParameters = array()) + { + if (null === $this->getDomain()) { + throw new Bitrix24Exception('domain not found, you must call setDomain method before'); + } + if (null === $this->getAccessToken()) { + throw new Bitrix24Exception('access token not found, you must call setAccessToken method before'); + } + if ('' === $methodName) { + throw new Bitrix24Exception('method name not found, you must set method name'); + } + + $url = 'https://' . $this->domain . '/rest/' . $methodName; + $additionalParameters['auth'] = $this->accessToken; + // save method parameters for debug + $this->methodParameters = $additionalParameters; + // is secure api-call? + $isSecureCall = false; + if (array_key_exists('state', $additionalParameters)) { + $isSecureCall = true; + } + // execute request + $this->log->info('call bitrix24 method', array( + 'BITRIX24_DOMAIN' => $this->domain, + 'METHOD_NAME' => $methodName, + 'METHOD_PARAMETERS' => $additionalParameters + )); + $requestResult = $this->executeRequest($url, $additionalParameters); + // check errors and throw exception if errors exists + $this->handleBitrix24APILevelErrors($requestResult, $methodName, $additionalParameters); + // handling security sign for secure api-call + if ($isSecureCall) { + if (array_key_exists('signature', $requestResult)) { + // check signature structure + if (strpos($requestResult['signature'], '.') === false) { + throw new Bitrix24SecurityException('security signature is corrupted'); + } + if (null === $this->getMemberId()) { + throw new Bitrix24Exception('member-id not found, you must call setMemberId method before'); + } + if (null === $this->getApplicationSecret()) { + throw new Bitrix24Exception('application secret not found, you must call setApplicationSecret method before'); + } + // prepare + $key = md5($this->getMemberId() . $this->getApplicationSecret()); + $delimiterPosition = strrpos($requestResult['signature'], '.'); + $dataToDecode = substr($requestResult['signature'], 0, $delimiterPosition); + $signature = base64_decode(substr($requestResult['signature'], $delimiterPosition + 1)); + // compare signatures + $hash = hash_hmac('sha256', $dataToDecode, $key, true); + if ($hash !== $signature) { + throw new Bitrix24SecurityException('security signatures not same, bad request'); + } + // decode + $arClearData = json_decode(base64_decode($dataToDecode), true); + // handling json_decode errors + $jsonErrorCode = json_last_error(); + if (null === $arClearData && (JSON_ERROR_NONE !== $jsonErrorCode)) { + /** + * @todo add function json_last_error_msg() + */ + $errorMsg = 'fatal error in function json_decode.' . PHP_EOL . 'Error code: ' . $jsonErrorCode . PHP_EOL; + throw new Bitrix24Exception($errorMsg); + } + // merge dirty and clear data + unset($arClearData['state']); + $requestResult ['result'] = array_merge($requestResult ['result'], $arClearData); + } else { + throw new Bitrix24SecurityException('security signature in api-response not found'); + } + } + return $requestResult; } } diff --git a/src/classes/crm/deal/deal.php b/src/classes/crm/deal/deal.php index 63cbb263..ca812654 100644 --- a/src/classes/crm/deal/deal.php +++ b/src/classes/crm/deal/deal.php @@ -1,112 +1,114 @@ client->call( - 'crm.deal.add', - array( + /** + * Add a new deal to CRM + * @param array $fields array of fields + * @param array $params array of params + * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_add.php + * @return array + */ + public function add($fields = array(), $params = array()) + { + $fullResult = $this->client->call( + 'crm.deal.add', + array( 'fields' => $fields, 'params' => $params ) - ); - return $fullResult; - } + ); + return $fullResult; + } - /** - * delete deal by id - * @var $dealId integer deal identifier - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_delete.php - * @return array - */ - public function delete($dealId) - { - $fullResult = $this->client->call( - 'crm.deal.delete', - array('id' => $dealId) - ); - return $fullResult; - } + /** + * delete deal by id + * @var $dealId integer deal identifier + * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_delete.php + * @return array + */ + public function delete($dealId) + { + $fullResult = $this->client->call( + 'crm.deal.delete', + array('id' => $dealId) + ); + return $fullResult; + } - /** - * get list of deal fields with description - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_fields.php - * @return array - */ - public function fields() - { - $fullResult = $this->client->call( - 'crm.deal.fields' - ); - return $fullResult; - } + /** + * get list of deal fields with description + * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_fields.php + * @return array + */ + public function fields() + { + $fullResult = $this->client->call( + 'crm.deal.fields' + ); + return $fullResult; + } - /** - * get deal by id - * @var $dealId integer deal identifier - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_get.php - * @return array - */ - public function get($dealId) - { - $fullResult = $this->client->call( - 'crm.deal.get', - array('id' => $dealId) - ); - return $fullResult; - } + /** + * get deal by id + * @var $dealId integer deal identifier + * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_get.php + * @return array + */ + public function get($dealId) + { + $fullResult = $this->client->call( + 'crm.deal.get', + array('id' => $dealId) + ); + return $fullResult; + } - /** - * Get list of deal items. - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_list.php - * @param array $order - order of deal items - * @param array $filter - filter array - * @param array $select - array of collumns to select - * @param integer $start - entity number to start from (usually returned in 'next' field of previous 'crm.deal.list' API call) - * @return array - */ - public function getList($order = array(), $filter = array(), $select = array(), $start = 0) - { - $fullResult = $this->client->call( - 'crm.deal.list', - array( - 'order' => $order, - 'filter'=> $filter, - 'select'=> $select, - 'start' => $start - ) - ); - return $fullResult; - } + /** + * Get list of deal items. + * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_list.php + * @param array $order - order of deal items + * @param array $filter - filter array + * @param array $select - array of collumns to select + * @param integer $start - entity number to start from (usually returned in 'next' field of previous 'crm.deal.list' API call) + * @return array + */ + public function getList($order = array(), $filter = array(), $select = array(), $start = 0) + { + $fullResult = $this->client->call( + 'crm.deal.list', + array( + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $start + ) + ); + return $fullResult; + } - /** - * update deal by id - * @var $dealId integer deal identifier - * @var $dealFields array deal fields to update - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_update.php - * @return array - */ - public function update($dealId, $dealFields) - { - $fullResult = $this->client->call( - 'crm.deal.update', - array( - 'id' => $dealId, - 'fields' => $dealFields - ) - ); - return $fullResult; - } + /** + * update deal by id + * @var $dealId integer deal identifier + * @var $dealFields array deal fields to update + * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_update.php + * @return array + */ + public function update($dealId, $dealFields) + { + $fullResult = $this->client->call( + 'crm.deal.update', + array( + 'id' => $dealId, + 'fields' => $dealFields + ) + ); + return $fullResult; + } } diff --git a/src/contracts/ibitrix24.php b/src/contracts/ibitrix24.php index f980caa7..f47e9a40 100644 --- a/src/contracts/ibitrix24.php +++ b/src/contracts/ibitrix24.php @@ -5,6 +5,7 @@ * Date: 23.01.2016 * Time: 1:47 */ + namespace Bitrix24\Contracts; use Bitrix24\Bitrix24; @@ -29,155 +30,169 @@ */ interface iBitrix24 { - /** - * Create a object to work with Bitrix24 REST API service - * @param bool $isSaveRawResponse - if true raw response from bitrix24 will be available from method getRawResponse, this is debug mode - * @param null|LoggerInterface $obLogger - instance of \Monolog\Logger - * @throws Bitrix24Exception - * @return Bitrix24 - */ - public function __construct($isSaveRawResponse = false, LoggerInterface $obLogger = null); - - /** - * Get a random string to sign protected api-call. Use salt for argument "state" in secure api-call - * random string is a result of mt_rand function - * @return int - */ - public function getSecuritySignSalt(); - - /** - * Set member ID — portal GUID - * @param string $memberId - * @throws Bitrix24Exception - * @return true; - */ - public function setMemberId($memberId); - /** - * Get memeber ID - * @return string | null - */ - public function getMemberId(); - - /** - * Set redirect URI - * @param string $redirectUri - * @throws Bitrix24Exception - * @return true; - */ - public function setRedirectUri($redirectUri); - /** - * Get redirect URI - * @return string | null - */ - public function getRedirectUri(); - - /** - * Set access token - * @param string $accessToken - * @throws Bitrix24Exception - * @return true; - */ - public function setAccessToken($accessToken); - - /** - * Get access token - * @return string | null - */ - public function getAccessToken(); - - /** - * Set refresh token - * @param $refreshToken - * @throws Bitrix24Exception - * @return true; - */ - public function setRefreshToken($refreshToken); - /** - * Get refresh token - * @return string - */ - public function getRefreshToken(); - - /** - * Set domain - * @param $domain - * @throws Bitrix24Exception - * @return true; - */ - public function setDomain($domain); - - /** - * Get domain - * @return string | null - */ - public function getDomain(); - /** - * Set application scope - * @param array $applicationScope - * @return boolean - * @throws Bitrix24Exception - */ - public function setApplicationScope(array $applicationScope); - - /** - * Get application scope - */ - public function getApplicationScope(); - - /** - * Set application id - * @param string $applicationId - * @throws Bitrix24Exception - * @return true; - */ - public function setApplicationId($applicationId); - - /** - * Get application id - * @return string - */ - public function getApplicationId(); - - /** - * Set application secret - * @param string $applicationSecret - * @throws Bitrix24Exception - * @return true; - */ - public function setApplicationSecret($applicationSecret); - - /** - * Get application secret - * @return string - */ - public function getApplicationSecret(); - - /** - * Set custom cURL options, overriding default ones - * @link http://php.net/manual/en/function.curl-setopt.php - * @param array $options - array(CURLOPT_XXX => value1, CURLOPT_XXX2 => value2,...) - * @return bool - */ - public function setCustomCurlOptions($options); - - /** - * Return raw request, contain all cURL options array and API query. Data available after you try to call method call - * numbers of array keys is const of cURL module. Example: CURLOPT_RETURNTRANSFER = 19913 - * @return array | null - */ - public function getRawRequest(); - - /** - * Return result from function curl_getinfo. Data available after you try to call method call - * @return array | null - */ - public function getRequestInfo(); - - /** - * Return additional parameters of last api-call. Data available after you try to call method call - * @return array | null - */ - public function getMethodParameters(); + /** + * Max calls in one batch + */ + const MAX_BATCH_CALLS = 50; + + /** + * Default delay between batch calls (in msec) + */ + const BATCH_DELAY = 500000; + + /** + * Create a object to work with Bitrix24 REST API service + * @param bool $isSaveRawResponse - if true raw response from bitrix24 will be available from method getRawResponse, this is debug mode + * @param null|LoggerInterface $obLogger - instance of \Monolog\Logger + * @throws Bitrix24Exception + * @return Bitrix24 + */ + public function __construct($isSaveRawResponse = false, LoggerInterface $obLogger = null); + + /** + * Get a random string to sign protected api-call. Use salt for argument "state" in secure api-call + * random string is a result of mt_rand function + * @return int + */ + public function getSecuritySignSalt(); + + /** + * Set member ID — portal GUID + * @param string $memberId + * @throws Bitrix24Exception + * @return true; + */ + public function setMemberId($memberId); + + /** + * Get memeber ID + * @return string | null + */ + public function getMemberId(); + + /** + * Set redirect URI + * @param string $redirectUri + * @throws Bitrix24Exception + * @return true; + */ + public function setRedirectUri($redirectUri); + + /** + * Get redirect URI + * @return string | null + */ + public function getRedirectUri(); + + /** + * Set access token + * @param string $accessToken + * @throws Bitrix24Exception + * @return true; + */ + public function setAccessToken($accessToken); + + /** + * Get access token + * @return string | null + */ + public function getAccessToken(); + + /** + * Set refresh token + * @param $refreshToken + * @throws Bitrix24Exception + * @return true; + */ + public function setRefreshToken($refreshToken); + + /** + * Get refresh token + * @return string + */ + public function getRefreshToken(); + + /** + * Set domain + * @param $domain + * @throws Bitrix24Exception + * @return true; + */ + public function setDomain($domain); + + /** + * Get domain + * @return string | null + */ + public function getDomain(); + + /** + * Set application scope + * @param array $applicationScope + * @return boolean + * @throws Bitrix24Exception + */ + public function setApplicationScope(array $applicationScope); + + /** + * Get application scope + */ + public function getApplicationScope(); + + /** + * Set application id + * @param string $applicationId + * @throws Bitrix24Exception + * @return true; + */ + public function setApplicationId($applicationId); + + /** + * Get application id + * @return string + */ + public function getApplicationId(); + + /** + * Set application secret + * @param string $applicationSecret + * @throws Bitrix24Exception + * @return true; + */ + public function setApplicationSecret($applicationSecret); + + /** + * Get application secret + * @return string + */ + public function getApplicationSecret(); + + /** + * Set custom cURL options, overriding default ones + * @link http://php.net/manual/en/function.curl-setopt.php + * @param array $options - array(CURLOPT_XXX => value1, CURLOPT_XXX2 => value2,...) + * @return bool + */ + public function setCustomCurlOptions($options); + + /** + * Return raw request, contain all cURL options array and API query. Data available after you try to call method call + * numbers of array keys is const of cURL module. Example: CURLOPT_RETURNTRANSFER = 19913 + * @return array | null + */ + public function getRawRequest(); + + /** + * Return result from function curl_getinfo. Data available after you try to call method call + * @return array | null + */ + public function getRequestInfo(); + + /** + * Return additional parameters of last api-call. Data available after you try to call method call + * @return array | null + */ + public function getMethodParameters(); /** * Execute Bitrix24 REST API method @@ -199,15 +214,15 @@ public function getMethodParameters(); * * @return array */ - public function call($methodName, array $additionalParameters = array()); + public function call($methodName, array $additionalParameters = array()); - /** - * Get raw response from Bitrix24 before json_decode call, method available only in debug mode. - * To activate debug mode you must before set to true flag isSaveRawResponse in class construct - * @throws Bitrix24Exception - * @return string - */ - public function getRawResponse(); + /** + * Get raw response from Bitrix24 before json_decode call, method available only in debug mode. + * To activate debug mode you must before set to true flag isSaveRawResponse in class construct + * @throws Bitrix24Exception + * @return string + */ + public function getRawResponse(); /** * Get new access token @@ -226,7 +241,7 @@ public function getRawResponse(); * @throws Bitrix24PaymentRequiredException * */ - public function getNewAccessToken(); + public function getNewAccessToken(); /** * Authorize and get first access token @@ -247,7 +262,7 @@ public function getNewAccessToken(); * @throws Bitrix24PaymentRequiredException * */ - public function getFirstAccessToken($code); + public function getFirstAccessToken($code); /** * Check is access token expire, call list of all available api-methods from B24 portal with current access token @@ -266,48 +281,79 @@ public function getFirstAccessToken($code); * * @return boolean */ - public function isAccessTokenExpire(); - - /** - * Get list of all methods available for current application - * @param array | null $applicationScope - * @param bool $isFull - * @return array - * @throws Bitrix24Exception - */ - public function getAvailableMethods(array $applicationScope = array(), $isFull = false); - - /** - * get list of scope for current application from bitrix24 api - * @param bool $isFull - * @throws Bitrix24Exception - * @return array - */ - public function getScope($isFull=false); - - /** - * set CURL request count retries - * @param $retriesCnt - * @return boolean - */ - public function setRetriesToConnectCount($retriesCnt = 1); - - /** - * set retries to connect timeout in microseconds - * @param $microseconds - * @return boolean - */ - public function setRetriesToConnectTimeout($microseconds = 1000000); - - /** - * get CURL request count retries - * @return int - */ - public function getRetriesToConnectCount(); - - /** - * get retries to connect timeout in microseconds - * @return mixed - */ - public function getRetriesToConnectTimeout(); + public function isAccessTokenExpire(); + + /** + * Get list of all methods available for current application + * @param array | null $applicationScope + * @param bool $isFull + * @return array + * @throws Bitrix24Exception + */ + public function getAvailableMethods(array $applicationScope = array(), $isFull = false); + + /** + * get list of scope for current application from bitrix24 api + * @param bool $isFull + * @throws Bitrix24Exception + * @return array + */ + public function getScope($isFull = false); + + /** + * set CURL request count retries + * @param $retriesCnt + * @return boolean + */ + public function setRetriesToConnectCount($retriesCnt = 1); + + /** + * set retries to connect timeout in microseconds + * @param $microseconds + * @return boolean + */ + public function setRetriesToConnectTimeout($microseconds = 1000000); + + /** + * get CURL request count retries + * @return int + */ + public function getRetriesToConnectCount(); + + /** + * get retries to connect timeout in microseconds + * @return mixed + */ + public function getRetriesToConnectTimeout(); + + /** + * Add call to batch. If [[$callback]] parameter is set, it will receive call result as first parameter. + * + * @param string $method + * @param array $parameters + * @param callable|null $callback + * + * @return string Unique call ID. + */ + public function addBatchCall($method, array $parameters = array(), callable $callback = null); + + /** + * Process batch calls. + * + * @param int $halt Halt batch on error + * @param int $delay Delay between batch calls (in msec) + * + * @throws Bitrix24Exception + * @throws Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + */ + public function processBatchCalls($halt = 0, $delay = self::BATCH_DELAY); + + /** + * Return true, if we have unprocessed batch calls. + * + * @return bool + */ + public function hasBatchCalls(); } \ No newline at end of file From d67ab10b26f50eadbdf55ba3fa33fa449f93cd96 Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Sat, 8 Jul 2017 15:31:03 +0300 Subject: [PATCH 093/647] fix changes --- CHANGELOG.md | 7 +++++++ README.md | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cef61283..829d6230 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,11 @@ # bitrix24-php-sdk change log +## 0.5.4 (8.07.2017) +* add Callback for expired token. Fix pullrequest#63 by valga +* add method `update` in class `Bitrix24\CRM\Product` +* increased curl time out +* add new scope `placement` in class `Bitrix24\Presets\Scope` +* add batch calls method to bitrix24 api client interface + ## 0.5.3 (20.05.2017) * add class `Bitrix24\Placement\Placement` * add preset `Bitrix24\Presets\Placement\Placement` with placement codes diff --git a/README.md b/README.md index 19624990..bb2bbc92 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ bitrix24-php-sdk [![Build Status](https://travis-ci.org/mesilov/bitrix24-php-sdk.svg?branch=master)](https://travis-ci.org/mesilov/bitrix24-php-sdk) ================ -[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/mesilov/bitrix24-php-sdk?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![License](https://poser.pugx.org/mesilov/bitrix24-php-sdk/license.svg)](https://packagist.org/packages/mesilov/bitrix24-php-sdk) [![Total Downloads](https://poser.pugx.org/mesilov/bitrix24-php-sdk/downloads.svg)](https://packagist.org/packages/mesilov/bitrix24-php-sdk) +[![License](https://poser.pugx.org/mesilov/bitrix24-php-sdk/license.svg)](https://packagist.org/packages/mesilov/bitrix24-php-sdk) [![Total Downloads](https://poser.pugx.org/mesilov/bitrix24-php-sdk/downloads.svg)](https://packagist.org/packages/mesilov/bitrix24-php-sdk) A powerfull PHP library for the Bitrix24 REST API From c4af021eab6221156ef75c01f986502762e30e60 Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Sat, 8 Jul 2017 15:51:00 +0300 Subject: [PATCH 094/647] task#66 fix tests --- src/stub/bitrix24.php | 706 ++++++++++++++++++++++-------------------- 1 file changed, 372 insertions(+), 334 deletions(-) diff --git a/src/stub/bitrix24.php b/src/stub/bitrix24.php index ceeadaf8..5a19d016 100644 --- a/src/stub/bitrix24.php +++ b/src/stub/bitrix24.php @@ -1,4 +1,5 @@ value1, CURLOPT_XXX2 => value2,...) - * - * @return bool - */ - public function setCustomCurlOptions($options) - { - } - - /** - * Return raw request, contain all cURL options array and API query. Data available after you try to call method call - * numbers of array keys is const of cURL module. Example: CURLOPT_RETURNTRANSFER = 19913 - * - * @return array | null - */ - public function getRawRequest() - { - } - - /** - * Return result from function curl_getinfo. Data available after you try to call method call - * - * @return array | null - */ - public function getRequestInfo() - { - } - - /** - * Return additional parameters of last api-call. Data available after you try to call method call - * - * @return array | null - */ - public function getMethodParameters() - { - } + /** + * SDK version + */ + const VERSION = '1.0'; + + /** + * Create a object to work with Bitrix24 REST API service + * + * @param bool $isSaveRawResponse - if true raw response from bitrix24 will be available from method getRawResponse, this is debug mode + * @param null|LoggerInterface $obLogger - instance of \Monolog\Logger + * + * @throws Bitrix24Exception + * + * @return Bitrix24 + */ + public function __construct($isSaveRawResponse = false, LoggerInterface $obLogger = null) + { + } + + /** + * Get a random string to sign protected api-call. Use salt for argument "state" in secure api-call + * random string is a result of mt_rand function + * + * @return int + */ + public function getSecuritySignSalt() + { + } + + /** + * Set member ID — portal GUID + * + * @param string $memberId + * + * @throws Bitrix24Exception + * + * @return true; + */ + public function setMemberId($memberId) + { + } + + /** + * Get memeber ID + * + * @return string | null + */ + public function getMemberId() + { + } + + /** + * Set redirect URI + * + * @param string $redirectUri + * + * @throws Bitrix24Exception + * + * @return true; + */ + public function setRedirectUri($redirectUri) + { + } + + /** + * Get redirect URI + * + * @return string | null + */ + public function getRedirectUri() + { + } + + /** + * Set access token + * + * @param string $accessToken + * + * @throws Bitrix24Exception + * + * @return true + */ + public function setAccessToken($accessToken) + { + } + + /** + * Get access token + * + * @return string | null + */ + public function getAccessToken() + { + } + + /** + * Set refresh token + * + * @param $refreshToken + * + * @throws Bitrix24Exception + * + * @return true; + */ + public function setRefreshToken($refreshToken) + { + } + + /** + * Get refresh token + * + * @return string + */ + public function getRefreshToken() + { + } + + /** + * Set domain + * + * @param $domain + * + * @throws Bitrix24Exception + * + * @return true + */ + public function setDomain($domain) + { + } + + /** + * Get domain + * + * @return string | null + */ + public function getDomain() + { + } + + /** + * Set application scope + * + * @param array $applicationScope + * + * @return boolean + * + * @throws Bitrix24Exception + */ + public function setApplicationScope(array $applicationScope) + { + } + + /** + * Get application scope + * + * @return array + */ + public function getApplicationScope() + { + } + + /** + * Set application id + * + * @param string $applicationId + * + * @throws Bitrix24Exception + * + * @return true + */ + public function setApplicationId($applicationId) + { + } + + /** + * Get application id + * + * @return string + */ + public function getApplicationId() + { + } + + /** + * Set application secret + * + * @param string $applicationSecret + * + * @throws Bitrix24Exception + * + * @return true; + */ + public function setApplicationSecret($applicationSecret) + { + } + + /** + * Get application secret + * + * @return string + */ + public function getApplicationSecret() + { + } + + /** + * Set custom cURL options, overriding default ones + * @link http://php.net/manual/en/function.curl-setopt.php + * + * @param array $options - array(CURLOPT_XXX => value1, CURLOPT_XXX2 => value2,...) + * + * @return bool + */ + public function setCustomCurlOptions($options) + { + } + + /** + * Return raw request, contain all cURL options array and API query. Data available after you try to call method call + * numbers of array keys is const of cURL module. Example: CURLOPT_RETURNTRANSFER = 19913 + * + * @return array | null + */ + public function getRawRequest() + { + } + + /** + * Return result from function curl_getinfo. Data available after you try to call method call + * + * @return array | null + */ + public function getRequestInfo() + { + } + + /** + * Return additional parameters of last api-call. Data available after you try to call method call + * + * @return array | null + */ + public function getMethodParameters() + { + } /** * Execute Bitrix24 REST API method @@ -289,21 +290,21 @@ public function getMethodParameters() * * @return array */ - public function call($methodName, array $additionalParameters = array()) - { - } + public function call($methodName, array $additionalParameters = array()) + { + } - /** - * Get raw response from Bitrix24 before json_decode call, method available only in debug mode. - * To activate debug mode you must before set to true flag isSaveRawResponse in class construct - * - * @throws Bitrix24Exception - * - * @return string - */ - public function getRawResponse() - { - } + /** + * Get raw response from Bitrix24 before json_decode call, method available only in debug mode. + * To activate debug mode you must before set to true flag isSaveRawResponse in class construct + * + * @throws Bitrix24Exception + * + * @return string + */ + public function getRawResponse() + { + } /** * Get new access token @@ -322,9 +323,9 @@ public function getRawResponse() * @throws Bitrix24PaymentRequiredException * */ - public function getNewAccessToken() - { - } + public function getNewAccessToken() + { + } /** * Authorize and get first access token @@ -345,9 +346,9 @@ public function getNewAccessToken() * @throws Bitrix24PaymentRequiredException * */ - public function getFirstAccessToken($code) - { - } + public function getFirstAccessToken($code) + { + } /** * Check is access token expire, call list of all available api-methods from B24 portal with current access token @@ -366,75 +367,112 @@ public function getFirstAccessToken($code) * * @return boolean */ - public function isAccessTokenExpire() - { - } - - /** - * Get list of all methods available for current application - * - * @param array | null $applicationScope - * @param bool $isFull - * - * @return array - * - * @throws Bitrix24Exception - */ - public function getAvailableMethods(array $applicationScope = array(), $isFull = false) - { - } - - /** - * get list of scope for current application from bitrix24 api - * - * @param bool $isFull - * - * @throws Bitrix24Exception - * - * @return array - */ - public function getScope($isFull=false) - { - } - - /** - * set CURL request count retries - * - * @param $retriesCnt - * - * @return boolean - */ - public function setRetriesToConnectCount($retriesCnt = 1) - { - } - - /** - * set retries to connect timeout in microseconds - * - * @param $microseconds - * - * @return boolean - */ - public function setRetriesToConnectTimeout($microseconds = 1000000) - { - } - - /** - * get CURL request count retries - * - * @return int - */ - public function getRetriesToConnectCount() - { - } - - /** - * get retries to connect timeout in microseconds - * - * @return mixed - */ - public function getRetriesToConnectTimeout() - { - } + public function isAccessTokenExpire() + { + } + + /** + * Get list of all methods available for current application + * + * @param array | null $applicationScope + * @param bool $isFull + * + * @return array + * + * @throws Bitrix24Exception + */ + public function getAvailableMethods(array $applicationScope = array(), $isFull = false) + { + } + + /** + * get list of scope for current application from bitrix24 api + * + * @param bool $isFull + * + * @throws Bitrix24Exception + * + * @return array + */ + public function getScope($isFull = false) + { + } + + /** + * set CURL request count retries + * + * @param $retriesCnt + * + * @return boolean + */ + public function setRetriesToConnectCount($retriesCnt = 1) + { + } + + /** + * set retries to connect timeout in microseconds + * + * @param $microseconds + * + * @return boolean + */ + public function setRetriesToConnectTimeout($microseconds = 1000000) + { + } + + /** + * get CURL request count retries + * + * @return int + */ + public function getRetriesToConnectCount() + { + } + + /** + * get retries to connect timeout in microseconds + * + * @return mixed + */ + public function getRetriesToConnectTimeout() + { + } + + /** + * Add call to batch. If [[$callback]] parameter is set, it will receive call result as first parameter. + * + * @param string $method + * @param array $parameters + * @param callable|null $callback + * + * @return string Unique call ID. + */ + public function addBatchCall($method, array $parameters = array(), callable $callback = null) + { + } + + /** + * Return true, if we have unprocessed batch calls. + * + * @return bool + */ + public function hasBatchCalls() + { + } + + /** + * Process batch calls. + * + * @param int $halt Halt batch on error + * @param int $delay Delay between batch calls (in msec) + * + * @throws Bitrix24Exception + * @throws Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + */ + public function processBatchCalls($halt = 0, $delay = self::BATCH_DELAY) + { + } } From b52ee1675c998ee0a3ad086dcf72e1dd73097635 Mon Sep 17 00:00:00 2001 From: yugene Date: Wed, 12 Jul 2017 00:37:02 +0300 Subject: [PATCH 095/647] Params for deal update --- src/classes/crm/deal/deal.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/classes/crm/deal/deal.php b/src/classes/crm/deal/deal.php index ca812654..96de0c3c 100644 --- a/src/classes/crm/deal/deal.php +++ b/src/classes/crm/deal/deal.php @@ -93,18 +93,21 @@ public function getList($order = array(), $filter = array(), $select = array(), /** * update deal by id - * @var $dealId integer deal identifier - * @var $dealFields array deal fields to update + * @param integer $dealId integer deal identifier + * @param array $dealFields array deal fields to update + * @param array $params Set of parameters. REGISTER_SONET_EVENT - performs registration of a change event in a deal in the Activity Stream. + * The deals's Responsible person will also receive notification. * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_update.php * @return array */ - public function update($dealId, $dealFields) + public function update($dealId, $dealFields, $params = array()) { $fullResult = $this->client->call( 'crm.deal.update', array( 'id' => $dealId, - 'fields' => $dealFields + 'fields' => $dealFields, + 'params' => $params ) ); return $fullResult; From c1c23afec4fbdcb1b7c9bcb21a198bf5dd09c91f Mon Sep 17 00:00:00 2001 From: Leonid Volokitin Date: Sat, 9 Sep 2017 09:53:32 +0300 Subject: [PATCH 096/647] Added all methods for sonetgroup. Class have moved to the classes/sonet folder --- src/classes/sonet/sonetgroup.php | 179 +++++++++++++++++++++++++++++++ src/classes/sonetgroup.php | 36 ------- 2 files changed, 179 insertions(+), 36 deletions(-) create mode 100644 src/classes/sonet/sonetgroup.php delete mode 100644 src/classes/sonetgroup.php diff --git a/src/classes/sonet/sonetgroup.php b/src/classes/sonet/sonetgroup.php new file mode 100644 index 00000000..9dcd6904 --- /dev/null +++ b/src/classes/sonet/sonetgroup.php @@ -0,0 +1,179 @@ +client->call('sonet_group.get', + array( + 'ORDER' => $order, + 'FILTER'=> $filter, + )); + return $result; + } + + /** + * @param $name + * @param $initiate_perms + * @param $arFields + * @link https://dev.1c-bitrix.ru/rest_help/socialnetwork/sonet_group/sonet_group_create.php + * @throws Bitrix24Exception + * @return array + */ + public function Create($name, $initiate_perms, $arFields) + { + $result = $this->client->call('sonet_group.create', + array_merge( + array( + 'NAME' => $name, + 'INITIATE_PERMS' => $initiate_perms + ), + $arFields + )); + return $result; + } + + /** + * @param $group_id + * @param $arFields + * @link https://dev.1c-bitrix.ru/api_help/socialnetwork/classes/CSocNetGroup/Update.php + * @throws Bitrix24Exception + * @return array + */ + public function Update($group_id, $arFields) + { + $result = $this->client->call('sonet_group.update', + array_merge( + array('GROUP_ID' => $group_id), + $arFields + )); + return $result; + } + + /** + * @param $group_id + * @link https://dev.1c-bitrix.ru/rest_help/socialnetwork/sonet_group/sonet_group_delete.php + * @throws Bitrix24Exception + * @return array + */ + public function Delete($group_id) + { + $result = $this->client->call('sonet_group.delete', + array( + 'GROUP_ID' => $group_id + )); + return $result; + } + + /** + * @param $group_id + * @param $user_id + * @link https://dev.1c-bitrix.ru/rest_help/socialnetwork/sonet_group/sonet_group_setowner.php + * @throws Bitrix24Exception + * @return array + */ + public function SetOwner($group_id, $user_id) + { + $result = $this->client->call('sonet_group.setowner', + array( + 'GROUP_ID' => $group_id, + 'USER_ID'=> $user_id + )); + return $result; + } + + /** + * @param $id + * @link https://dev.1c-bitrix.ru/rest_help/socialnetwork/sonet_group/sonet_group_user_get.php + * @throws Bitrix24Exception + * @return array + */ + public function UserGet($id) + { + $result = $this->client->call('sonet_group.user.get', + array( + 'ID' => $id + ) + ); + return $result; + } + + /** + * @param $group_id + * @param $user_id + * @param $message + * @link https://dev.1c-bitrix.ru/rest_help/socialnetwork/sonet_group/sonet_group_user_invite.php + * @throws Bitrix24Exception + * @return array + */ + public function Invate($group_id, $user_id, $message) + { + $result = $this->client->call('sonet_group.user.invite', + array( + 'GROUP_ID' => $group_id, + 'USER_ID'=> $user_id, + 'MESSAGE'=> $message + ) + ); + return $result; + } + + /** + * @param $group_id + * @param $message + * @link https://dev.1c-bitrix.ru/rest_help/socialnetwork/sonet_group/sonet_group_user_request.php + * @throws Bitrix24Exception + * @return array + */ + public function Request($group_id, $message) + { + $result = $this->client->call('sonet_group.user.request', + array( + 'GROUP_ID' => $group_id, + 'MESSAGE'=> $message + ) + ); + return $result; + } + + /** + * @link https://dev.1c-bitrix.ru/rest_help/socialnetwork/sonet_group/sonet_group_user_groups.php + * @throws Bitrix24Exception + * @return array + */ + public function UserGroups() + { + $result= $this->client->call('sonet_group.user.groups'); + return $result; + } + + /** + * @param $group_id + * @param $feature + * @param $operation + * @link https://dev.1c-bitrix.ru/rest_help/socialnetwork/sonet_group/sonet_group_feature_access.php + * @throws Bitrix24Exception + * @return array + */ + public function FeatureAccess($group_id, $feature, $operation) + { + $result = $this->client->call('sonet_group.feature.access', + array( + 'GROUP_ID' => $group_id, + 'FEATURE' => $feature, + 'OPERATION' => $operation + )); + return $result; + } +} \ No newline at end of file diff --git a/src/classes/sonetgroup.php b/src/classes/sonetgroup.php deleted file mode 100644 index 1dd317fa..00000000 --- a/src/classes/sonetgroup.php +++ /dev/null @@ -1,36 +0,0 @@ -client->call('sonet_group.get', - array( - 'ORDER' => $ORDER, - 'FILTER'=> $FILTER, - )); - return $result; - } - - /** - * @param $FILTER - * @return array - */ - public function UserGet($FILTER) - { - $result= $this->client->call('sonet_group.user.get', - $FILTER - ); - return $result; - } -} \ No newline at end of file From 18e8f171386cd9d4d14246b7fa9e127093a2cd2a Mon Sep 17 00:00:00 2001 From: Leonid Volokitin Date: Sat, 9 Sep 2017 09:58:54 +0300 Subject: [PATCH 097/647] Minor fix --- src/classes/sonet/sonetgroup.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/classes/sonet/sonetgroup.php b/src/classes/sonet/sonetgroup.php index 9dcd6904..c857cf12 100644 --- a/src/classes/sonet/sonetgroup.php +++ b/src/classes/sonet/sonetgroup.php @@ -9,7 +9,7 @@ class SonetGroup extends Bitrix24Entity /** * @param $order * @param $filter - * @link https://dev.1c-bitrix.ru/rest_help/socialnetwork/sonet_group/sonet_group_create.php + * @link https://dev.1c-bitrix.ru/rest_help/socialnetwork/sonet_group/sonet_group_get.php * @throws Bitrix24Exception * @return array */ @@ -128,7 +128,7 @@ public function Invate($group_id, $user_id, $message) ); return $result; } - + /** * @param $group_id * @param $message From 5ddd89f8bf0d3b9f67db599b4b51f0feaf65992c Mon Sep 17 00:00:00 2001 From: camaxtly Date: Thu, 28 Sep 2017 22:20:09 +0300 Subject: [PATCH 098/647] add update method --- src/classes/crm/contact/userfield.php | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/classes/crm/contact/userfield.php b/src/classes/crm/contact/userfield.php index 6951d811..88803309 100644 --- a/src/classes/crm/contact/userfield.php +++ b/src/classes/crm/contact/userfield.php @@ -71,4 +71,27 @@ public function add($fields = array()) ); return $fullResult; } + + + /** + * Updates userfield + * + * @param $id + * @param array $fields + * + * @link https://dev.1c-bitrix.ru/rest_help/crm/contacts/crm_contact_userfield_update.php + * @return array + */ + public function update($id, $fields = array()) + { + $fullResult = $this->client->call( + 'crm.contact.userfield.update', + array( + 'id' => $id, + 'fields' => $fields + ) + ); + + return $fullResult; + } } From c2368d397af1132ebd8d04d2f1f8bfaf4b5eae71 Mon Sep 17 00:00:00 2001 From: camaxtly Date: Tue, 3 Oct 2017 21:28:57 +0300 Subject: [PATCH 099/647] add update method --- src/classes/crm/lead/userfield.php | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/classes/crm/lead/userfield.php b/src/classes/crm/lead/userfield.php index 720cfbc3..60eab52e 100644 --- a/src/classes/crm/lead/userfield.php +++ b/src/classes/crm/lead/userfield.php @@ -83,4 +83,26 @@ public function add($fields = array()) ); return $fullResult; } + + /** + * Updates userfield + * + * @param $id + * @param array $fields + * + * @link https://dev.1c-bitrix.ru/rest_help/crm/leads/crm_lead_userfield_update.php + * @return array + */ + public function update($id, $fields = array()) + { + $fullResult = $this->client->call( + 'crm.lead.userfield.update', + array( + 'id' => $id, + 'fields' => $fields + ) + ); + + return $fullResult; + } } \ No newline at end of file From bdcf5d0d1bb4ba7b2eee5a1d9f918fc429e149d9 Mon Sep 17 00:00:00 2001 From: camaxtly Date: Tue, 3 Oct 2017 21:30:45 +0300 Subject: [PATCH 100/647] add bizproc activities methods --- src/classes/bizproc/Activity.php | 125 +++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 src/classes/bizproc/Activity.php diff --git a/src/classes/bizproc/Activity.php b/src/classes/bizproc/Activity.php new file mode 100644 index 00000000..074b7895 --- /dev/null +++ b/src/classes/bizproc/Activity.php @@ -0,0 +1,125 @@ +client->call('bizproc.activity.add', + array( + 'CODE' => $code, + 'HANDLER' => $handler, + 'AUTH_USER_ID' => $userId, + 'USE_SUBSCRIPTION' => $subscription, + 'NAME' => $arName, + 'DESCRIPTION' => $arDescription, + 'PROPERTIES' => $arProps, + 'RETURN_PROPERTIES' => $arReturnProps, + 'DOCUMENT_TYPE' => $arDocType, + 'FILTER' => $arFilter, + )); + return $arResult['result']; + } + + + /** + * get list of installed activities + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + */ + public function getList() + { + $arResult = $this->client->call('bizproc.activity.list', + array() + ); + return $arResult['result']; + } + + /** + * delete activity + * + * @param $code string + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + */ + public function delete($code) + { + $arResult = $this->client->call('bizproc.activity.delete', + array( + 'code' => $code + ) + ); + return $arResult['result']; + } + +} \ No newline at end of file From 0d8e1112978d5448816fbe7b9559fa11a3a049ee Mon Sep 17 00:00:00 2001 From: Abyr Valg Date: Fri, 6 Oct 2017 11:18:42 +0300 Subject: [PATCH 101/647] Add Bitrix24PortalRenamedException --- src/bitrix24.php | 13 +++++++++++-- src/contracts/ibitrix24.php | 5 +++++ src/exceptions/bitrix24exception.php | 1 + .../bitrix24portalrenamedexception.php | 18 ++++++++++++++++++ 4 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 src/exceptions/bitrix24portalrenamedexception.php diff --git a/src/bitrix24.php b/src/bitrix24.php index ce39a6ae..1e547d32 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -19,6 +19,7 @@ use Bitrix24\Exceptions\Bitrix24MethodNotFoundException; use Bitrix24\Exceptions\Bitrix24PaymentRequiredException; use Bitrix24\Exceptions\Bitrix24PortalDeletedException; +use Bitrix24\Exceptions\Bitrix24PortalRenamedException; use Bitrix24\Exceptions\Bitrix24SecurityException; use Bitrix24\Exceptions\Bitrix24TokenIsExpiredException; use Bitrix24\Exceptions\Bitrix24TokenIsInvalidException; @@ -238,7 +239,7 @@ public function getMethodParameters() * @throws Bitrix24WrongClientException * @throws Bitrix24MethodNotFoundException * @throws Bitrix24PaymentRequiredException - * + * @throws Bitrix24PortalRenamedException */ public function getNewAccessToken() { @@ -711,6 +712,7 @@ public function setRetriesToConnectTimeout($microseconds = 1000000) * @throws Bitrix24WrongClientException * @throws Bitrix24MethodNotFoundException * @throws Bitrix24PaymentRequiredException + * @throws Bitrix24PortalRenamedException */ protected function handleBitrix24APILevelErrors( $arRequestResult, @@ -739,6 +741,8 @@ protected function handleBitrix24APILevelErrors( throw new Bitrix24TokenIsExpiredException($errorMsg); case 'PAYMENT_REQUIRED': throw new Bitrix24PaymentRequiredException($errorMsg); + case 'NO_AUTH_FOUND': + throw new Bitrix24PortalRenamedException($errorMsg); default: throw new Bitrix24ApiException($errorMsg); } @@ -763,7 +767,7 @@ protected function handleBitrix24APILevelErrors( * @throws Bitrix24WrongClientException * @throws Bitrix24MethodNotFoundException * @throws Bitrix24PaymentRequiredException - * + * @throws Bitrix24PortalRenamedException */ public function getFirstAccessToken($code) { @@ -810,6 +814,7 @@ public function getFirstAccessToken($code) * @throws Bitrix24WrongClientException * @throws Bitrix24MethodNotFoundException * @throws Bitrix24PaymentRequiredException + * @throws Bitrix24PortalRenamedException * * @return boolean */ @@ -849,6 +854,7 @@ public function isAccessTokenExpire() * @throws Bitrix24Exception * @throws Bitrix24Exception * @throws Bitrix24PortalDeletedException + * @throws Bitrix24PortalRenamedException * @throws Bitrix24IoException * @throws Bitrix24EmptyResponseException */ @@ -885,6 +891,7 @@ public function getAvailableMethods(array $applicationScope = array(), $isFull = * @throws Bitrix24Exception * @throws Bitrix24Exception * @throws Bitrix24PortalDeletedException + * @throws Bitrix24PortalRenamedException * @throws Bitrix24IoException * @throws Bitrix24EmptyResponseException * @@ -1025,6 +1032,7 @@ public function processBatchCalls($halt = 0, $delay = self::BATCH_DELAY) * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException * @throws \Bitrix24\Exceptions\Bitrix24SecurityException * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException * @throws \Bitrix24\Exceptions\Bitrix24IoException @@ -1069,6 +1077,7 @@ public function call($methodName, array $additionalParameters = array()) * @throws Bitrix24PortalDeletedException * @throws Bitrix24IoException * @throws Bitrix24EmptyResponseException + * @throws Bitrix24PortalRenamedException * * @return array */ diff --git a/src/contracts/ibitrix24.php b/src/contracts/ibitrix24.php index f47e9a40..c328223f 100644 --- a/src/contracts/ibitrix24.php +++ b/src/contracts/ibitrix24.php @@ -14,6 +14,7 @@ use Bitrix24\Exceptions\Bitrix24PaymentRequiredException; use Bitrix24\Exceptions\Bitrix24EmptyResponseException; use Bitrix24\Exceptions\Bitrix24ApiException; +use Bitrix24\Exceptions\Bitrix24PortalRenamedException; use Bitrix24\Exceptions\Bitrix24TokenIsInvalidException; use Bitrix24\Exceptions\Bitrix24WrongClientException; use Bitrix24\Exceptions\Bitrix24MethodNotFoundException; @@ -209,6 +210,7 @@ public function getMethodParameters(); * @throws Bitrix24PaymentRequiredException * @throws Bitrix24SecurityException * @throws Bitrix24PortalDeletedException + * @throws Bitrix24PortalRenamedException * @throws Bitrix24IoException * @throws Bitrix24EmptyResponseException * @@ -232,6 +234,7 @@ public function getRawResponse(); * @throws Bitrix24Exception * @throws Bitrix24ApiException * @throws Bitrix24PortalDeletedException + * @throws Bitrix24PortalRenamedException * @throws Bitrix24IoException * @throws Bitrix24EmptyResponseException * @throws Bitrix24TokenIsInvalidException @@ -253,6 +256,7 @@ public function getNewAccessToken(); * @throws Bitrix24Exception * @throws Bitrix24ApiException * @throws Bitrix24PortalDeletedException + * @throws Bitrix24PortalRenamedException * @throws Bitrix24IoException * @throws Bitrix24EmptyResponseException * @throws Bitrix24TokenIsInvalidException @@ -271,6 +275,7 @@ public function getFirstAccessToken($code); * @throws Bitrix24Exception * @throws Bitrix24ApiException * @throws Bitrix24PortalDeletedException + * @throws Bitrix24PortalRenamedException * @throws Bitrix24IoException * @throws Bitrix24EmptyResponseException * @throws Bitrix24TokenIsInvalidException diff --git a/src/exceptions/bitrix24exception.php b/src/exceptions/bitrix24exception.php index 9b867bc3..68f6f75a 100644 --- a/src/exceptions/bitrix24exception.php +++ b/src/exceptions/bitrix24exception.php @@ -22,6 +22,7 @@ * \Bitrix24TokenIsInvalidException — The access token provided is invalid * \Bitrix24TokenIsExpiredException — The access token provided has expired * \Bitrix24PortalDeletedException — Bitrix24 portal deleted + * \Bitrix24PortalRenamedException — Bitrix24 portal renamed * \Bitrix24PaymentRequiredException — Bitrix24 application payment required * \Bitrix24SecurityException — Security errors for protected methods * diff --git a/src/exceptions/bitrix24portalrenamedexception.php b/src/exceptions/bitrix24portalrenamedexception.php new file mode 100644 index 00000000..6656f52d --- /dev/null +++ b/src/exceptions/bitrix24portalrenamedexception.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Bitrix24\Exceptions; + +/** + * Class Bitrix24PortalRenamedException + * @package Bitrix24 + */ +class Bitrix24PortalRenamedException extends Bitrix24ApiException +{ +} \ No newline at end of file From 87c5b86aa805c0c690b8faa8e67aa0a3e7d4e3c9 Mon Sep 17 00:00:00 2001 From: Stas B Date: Sun, 15 Oct 2017 11:42:39 +0300 Subject: [PATCH 102/647] Adding a pair of fields for the Lead --- src/presets/crm/lead/fields.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/presets/crm/lead/fields.php b/src/presets/crm/lead/fields.php index 797f1940..9b5c4174 100644 --- a/src/presets/crm/lead/fields.php +++ b/src/presets/crm/lead/fields.php @@ -141,10 +141,18 @@ class Fields * @var string Phone. Can be read, can be write */ const PHONE = 'PHONE'; + /** + * @var string Mobile phone. Can be read, can be write + */ + const PHONE_MOBILE = 'PHONE_MOBILE'; /** * @var string E-mail. Can be read, can be write */ const EMAIL = 'EMAIL'; + /** + * @var string Over e-mail. Can be read, can be write + */ + const EMAIL_OTHER = 'EMAIL_OTHER'; /** * @var string Website Can be read, can be write */ @@ -193,4 +201,4 @@ class Fields * @var string Can be read and write. */ const UTM_TERM = 'UTM_TERM'; -} \ No newline at end of file +} From ddeeb3e1ccba97420585b5a4afbfce173c45af63 Mon Sep 17 00:00:00 2001 From: camaxtly Date: Sun, 15 Oct 2017 21:04:52 +0300 Subject: [PATCH 103/647] add requisite support --- src/classes/crm/requisite/address.php | 131 +++++++++++++ src/classes/crm/requisite/bank.php | 148 ++++++++++++++ src/classes/crm/requisite/link.php | 143 ++++++++++++++ src/classes/crm/requisite/preset.php | 207 ++++++++++++++++++++ src/classes/crm/requisite/presetfield.php | 225 ++++++++++++++++++++++ src/classes/crm/requisite/requisite.php | 150 +++++++++++++++ src/classes/crm/requisite/userfield.php | 156 +++++++++++++++ 7 files changed, 1160 insertions(+) create mode 100644 src/classes/crm/requisite/address.php create mode 100644 src/classes/crm/requisite/bank.php create mode 100644 src/classes/crm/requisite/link.php create mode 100644 src/classes/crm/requisite/preset.php create mode 100644 src/classes/crm/requisite/presetfield.php create mode 100644 src/classes/crm/requisite/requisite.php create mode 100644 src/classes/crm/requisite/userfield.php diff --git a/src/classes/crm/requisite/address.php b/src/classes/crm/requisite/address.php new file mode 100644 index 00000000..a141e1c8 --- /dev/null +++ b/src/classes/crm/requisite/address.php @@ -0,0 +1,131 @@ +client->call( + 'crm.address.add', + array( + 'fields' => $fields, + ) + ); + return $fullResult; + } + + /** + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_address_delete.php + * + * @param array $fields array of fields + * + * @return array + * @throws Bitrix24Exception + */ + public function delete($fields) + { + $fullResult = $this->client->call( + 'crm.address.delete', + array('fields' => $fields) + ); + return $fullResult; + } + + /** + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_address_fields.php + * @return array + * @throws Bitrix24Exception + */ + public function fields() + { + $fullResult = $this->client->call( + 'crm.address.fields' + ); + return $fullResult; + } + + + /** + * Get list of requisite items. + * + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_address_list.php + * + * @param array $order - order of items + * @param array $filter - filter array + * @param array $select - array of collumns to select + * @param integer $start - entity number to start from (usually returned in 'next' field of previous + * 'crm.contact.list' API call) + * + * @return array + * @throws Bitrix24Exception + * + */ + public function getList($order = array(), $filter = array(), $select = array(), $start = 0) + { + $fullResult = $this->client->call( + 'crm.address.list', + array( + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $start + ) + ); + return $fullResult; + } + + + /** + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_address_update.php + * + * @param array $fields An array in format array("field"=>"value"[, ...]) containing values for the fields + * that need to be updated. The fields can be one or more of those returned by + * crm.contact.fields. + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + */ + public function update($fields = array()) + { + $fullResult = $this->client->call( + 'crm.address.update', + array( + 'fields' => $fields + ) + ); + return $fullResult; + } +} diff --git a/src/classes/crm/requisite/bank.php b/src/classes/crm/requisite/bank.php new file mode 100644 index 00000000..c02d82e9 --- /dev/null +++ b/src/classes/crm/requisite/bank.php @@ -0,0 +1,148 @@ +client->call( + 'crm.requisite.bankdetail.add', + array( + 'fields' => $fields, + ) + ); + return $fullResult; + } + + /** + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_bankdetail_delete.php + * + * @param integer $id of bank requisite + * + * @return array + * @throws Bitrix24Exception + */ + public function delete($id) + { + $fullResult = $this->client->call( + 'crm.requisite.bankdetail.delete', + array('id' => $id) + ); + return $fullResult; + } + + /** + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_bankdetail_fields.php + * @return array + * @throws Bitrix24Exception + */ + public function fields() + { + $fullResult = $this->client->call( + 'crm.requisite.bankdetail.fields' + ); + return $fullResult; + } + + /** + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_bankdetail_get.php + * + * @param integer $id of bank requisite + * + * @return array + * @throws Bitrix24Exception + */ + public function get($id) + { + $fullResult = $this->client->call( + 'crm.requisite.bankdetail.get', + array('id' => $id) + ); + return $fullResult; + } + + + /** + * Get list of requisite items. + * + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_bankdetail_list.php + * + * @param array $order - order of items + * @param array $filter - filter array + * @param array $select - array of collumns to select + * @param integer $start - entity number to start from (usually returned in 'next' field of previous + * 'crm.contact.list' API call) + * + * @return array + * @throws Bitrix24Exception + * + */ + public function getList($order = array(), $filter = array(), $select = array(), $start = 0) + { + $fullResult = $this->client->call( + 'crm.requisite.bankdetail.list', + array( + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $start + ) + ); + return $fullResult; + } + + + /** + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_bankdetail_update.php + * + * @param integer $id + * @param array $fields An array in format array("field"=>"value"[, ...]) containing values for the fields that + * need to be updated. The fields can be one or more of those returned by + * crm.requisite.bankdetail.fields + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + */ + public function update($id, $fields = array()) + { + $fullResult = $this->client->call( + 'crm.requisite.bankdetail.update', + array( + 'id' => $id, + 'fields' => $fields, + ) + ); + return $fullResult; + } +} diff --git a/src/classes/crm/requisite/link.php b/src/classes/crm/requisite/link.php new file mode 100644 index 00000000..05318278 --- /dev/null +++ b/src/classes/crm/requisite/link.php @@ -0,0 +1,143 @@ +client->call( + 'crm.requisite.link.fields' + ); + return $fullResult; + } + + /** + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_link_fields.php + * + * @param $entityTypeId (@see https://dev.1c-bitrix.ru/rest_help/crm/auxiliary/enum/crm_enum_ownertype.php) + * @param $entityId + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + */ + public function get($entityTypeId, $entityId) + { + $fullResult = $this->client->call( + 'crm.requisite.link.get', + array( + 'entityTypeId' => $entityTypeId, + 'entityId' => $entityId, + ) + ); + return $fullResult; + } + + /** + * Get list of requisite items. + * + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_link_list.php + * + * @param array $order - order of items + * @param array $filter - filter array + * @param integer $start - entity number to start from (usually returned in 'next' field of previous + * 'crm.contact.list' API call) + * + * @return array + * @throws Bitrix24Exception + * + */ + public function getList($order = array(), $filter = array(), $start = 0) + { + $fullResult = $this->client->call( + 'crm.requisite.link.list', + array( + 'order' => $order, + 'filter' => $filter, + 'start' => $start + ) + ); + return $fullResult; + } + + + /** + * Get list of requisite items. + * + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_link_register.php + * + * @param $fields + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + */ + public function register($fields) + { + $fullResult = $this->client->call( + 'crm.requisite.link.register', + array( + 'fields' => $fields, + ) + ); + return $fullResult; + } + + /** + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_link_unregister.php + * + * @param $entityTypeId (@see https://dev.1c-bitrix.ru/rest_help/crm/auxiliary/enum/crm_enum_ownertype.php) + * @param $entityId + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + */ + public function unregister($entityTypeId, $entityId) + { + $fullResult = $this->client->call( + 'crm.requisite.link.get', + array( + 'entityTypeId' => $entityTypeId, + 'entityId' => $entityId, + ) + ); + return $fullResult; + } +} diff --git a/src/classes/crm/requisite/preset.php b/src/classes/crm/requisite/preset.php new file mode 100644 index 00000000..bb03645c --- /dev/null +++ b/src/classes/crm/requisite/preset.php @@ -0,0 +1,207 @@ +client->call( + 'crm.requisite.preset.add', + array( + 'fields' => $fields, + ) + ); + return $fullResult; + } + + /** + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_countries.php + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + */ + public function countries() + { + $fullResult = $this->client->call( + 'crm.requisite.preset.countries' + ); + return $fullResult; + } + + /** + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_delete.php + * + * @param $id + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @internal param array $fields array of fields + * + */ + public function delete($id) + { + $fullResult = $this->client->call( + 'crm.requisite.preset.delete', + array('id' => $id) + ); + return $fullResult; + } + + /** + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_fields.php + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + */ + public function fields() + { + $fullResult = $this->client->call( + 'crm.requisite.preset.fields' + ); + return $fullResult; + } + + /** + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_get.php + * + * @param $id + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + */ + public function get($id) + { + $fullResult = $this->client->call( + 'crm.requisite.preset.get', + array( + 'id' => $id + ) + ); + return $fullResult; + } + + + /** + * Get list of requisite items. + * + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_list.php + * + * @param array $order - order of items + * @param array $filter - filter array + * @param array $select - array of collumns to select + * @param integer $start - entity number to start from (usually returned in 'next' field of previous + * 'crm.contact.list' API call) + * + * @return array + * @throws Bitrix24Exception + * + */ + public function getList($order = array(), $filter = array(), $select = array(), $start = 0) + { + $fullResult = $this->client->call( + 'crm.requisite.preset.list', + array( + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $start + ) + ); + return $fullResult; + } + + + /** + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_update.php + * + * @param $id + * @param array $fields An array in format array("field"=>"value"[, ...]) containing values for the fields + * that need to be updated. The fields can be one or more of those returned by + * crm.requisite.preset.fields + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + */ + public function update($id, $fields = array()) + { + $fullResult = $this->client->call( + 'crm.requisite.preset.update', + array( + 'id' => $id, + 'fields' => $fields + ) + ); + return $fullResult; + } +} diff --git a/src/classes/crm/requisite/presetfield.php b/src/classes/crm/requisite/presetfield.php new file mode 100644 index 00000000..053cdd5b --- /dev/null +++ b/src/classes/crm/requisite/presetfield.php @@ -0,0 +1,225 @@ +client->call( + 'crm.requisite.preset.field.add', + array( + 'preset' => $preset, + 'fields' => $fields, + ) + ); + return $fullResult; + } + + /** + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_field_availabletoadd.php + * + * @param array $preset + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + */ + public function availableToAdd($preset = array()) + { + $fullResult = $this->client->call( + 'crm.requisite.preset.field.availabletoadd', + array( + 'preset' => $preset, + ) + ); + return $fullResult; + } + + /** + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_field_delete.php + * + * @param $id + * + * @param $preset + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @internal param array $fields array of fields + */ + public function delete($id, $preset) + { + $fullResult = $this->client->call( + 'crm.requisite.preset.field.delete', + array( + 'id' => $id, + 'preset' => $preset + ) + ); + return $fullResult; + } + + /** + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_field_fields.php + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + */ + public function fields() + { + $fullResult = $this->client->call( + 'crm.requisite.preset.field.fields' + ); + return $fullResult; + } + + /** + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_field_get.php + * + * @param $id + * + * @param $preset + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + */ + public function get($id, $preset) + { + $fullResult = $this->client->call( + 'crm.requisite.preset.field.get', + array( + 'id' => $id, + 'preset' => $preset + ) + ); + return $fullResult; + } + + + /** + * Get list of requisite items. + * + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_field_list.php + * + * + * @param array $preset + * @param int $start + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + */ + public function getList($preset = array(), $start = 0) + { + $fullResult = $this->client->call( + 'crm.requisite.preset.field.list', + array( + 'preset' => $preset, + 'start' => $start + ) + ); + return $fullResult; + } + + + /** + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_update.php + * + * @param $id + * @param array $fields An array in format array("field"=>"value"[, ...]) containing values for the fields + * that need to be updated. The fields can be one or more of those returned by + * crm.requisite.preset.fields + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + */ + public function update($preset = array(), $fields = array()) + { + $fullResult = $this->client->call( + 'crm.requisite.preset.field.update', + array( + 'preset' => $preset, + 'fields' => $fields + ) + ); + return $fullResult; + } +} diff --git a/src/classes/crm/requisite/requisite.php b/src/classes/crm/requisite/requisite.php new file mode 100644 index 00000000..10ad1bfd --- /dev/null +++ b/src/classes/crm/requisite/requisite.php @@ -0,0 +1,150 @@ +client->call( + 'crm.requisite.add', + array( + 'fields' => $fields, + ) + ); + return $fullResult; + } + + /** + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_delete.php + * + * @param integer $id + * + * @return array + * @throws Bitrix24Exception + */ + public function delete($id) + { + $fullResult = $this->client->call( + 'crm.requisite.delete', + array('id' => $id) + ); + return $fullResult; + } + + /** + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_fields.php + * @return array + * @throws Bitrix24Exception + */ + public function fields() + { + $fullResult = $this->client->call( + 'crm.requisite.fields' + ); + return $fullResult; + } + + /** + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_get.php + * + * @param integer $id + * + * @return array + * @throws Bitrix24Exception + */ + public function get($id) + { + $fullResult = $this->client->call( + 'crm.requisite.get', + array('id' => $id) + ); + return $fullResult; + } + + + /** + * Get list of requisite items. + * + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_list.php + * + * @param array $order - order of items + * @param array $filter - filter array + * @param array $select - array of collumns to select + * @param integer $start - entity number to start from (usually returned in 'next' field of previous + * 'crm.requisite.list' API call) + * + * @return array + * @throws Bitrix24Exception + * + */ + public function getList($order = array(), $filter = array(), $select = array(), $start = 0) + { + $fullResult = $this->client->call( + 'crm.requisite.list', + array( + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $start + ) + ); + return $fullResult; + } + + + /** + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_update.php + * + * @param $id + * @param array $fields An array in format array("field"=>"value"[, ...]) containing values for the fields + * that need to be updated. The fields can be one or more of those returned by + * crm.requisite.fields. + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + */ + public function update($id, $fields = array()) + { + $fullResult = $this->client->call( + 'crm.requisite.update', + array( + 'id' => $id, + 'fields' => $fields + ) + ); + return $fullResult; + } +} diff --git a/src/classes/crm/requisite/userfield.php b/src/classes/crm/requisite/userfield.php new file mode 100644 index 00000000..21efd202 --- /dev/null +++ b/src/classes/crm/requisite/userfield.php @@ -0,0 +1,156 @@ +client->call( + 'crm.requisite.userfield.add', + array('fields' => $fields) + ); + return $fullResult; + } + + /** + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_userfield_delete.php + * + * @param integer $userfieldId + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + */ + public function delete($userfieldId) + { + $fullResult = $this->client->call( + 'crm.requisite.userfield.delete', + array('id' => $userfieldId) + ); + return $fullResult; + } + + /** + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_userfield_get.php + * + * @param integer $userfieldId + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + */ + public function get($userfieldId) + { + $fullResult = $this->client->call( + 'crm.requisite.userfield.get', + array('id' => $userfieldId) + ); + return $fullResult; + } + + /** + * Get list of user fields items. + * + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_userfield_list.php + * + * @param array $order - order of task items + * @param array $filter - filter array + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + */ + public function getList($order = array(), $filter = array()) + { + $fullResult = $this->client->call( + 'crm.requisite.userfield.list', + array( + 'order' => $order, + 'filter' => $filter + ) + ); + return $fullResult; + } + + + /** + * @param $id + * @param array $fields + * + * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_userfield_update.php + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + */ + public function update($id, $fields = array()) + { + $fullResult = $this->client->call( + 'crm.requisite.userfield.update', + array( + 'id' => $id, + 'fields' => $fields + ) + ); + + return $fullResult; + } +} From 7259b1f0e2f39e4dcf3b0d7c0d52b348b87a1c58 Mon Sep 17 00:00:00 2001 From: camaxtly Date: Sat, 21 Oct 2017 16:16:36 +0300 Subject: [PATCH 104/647] namespace changed --- src/classes/crm/requisite/address.php | 2 +- src/classes/crm/requisite/bank.php | 2 +- src/classes/crm/requisite/link.php | 2 +- src/classes/crm/requisite/preset.php | 2 +- src/classes/crm/requisite/presetfield.php | 2 +- src/classes/crm/requisite/requisite.php | 2 +- src/classes/crm/requisite/userfield.php | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/classes/crm/requisite/address.php b/src/classes/crm/requisite/address.php index a141e1c8..34b4a1ae 100644 --- a/src/classes/crm/requisite/address.php +++ b/src/classes/crm/requisite/address.php @@ -1,6 +1,6 @@ Date: Tue, 24 Oct 2017 23:09:27 +0300 Subject: [PATCH 105/647] issue#76 add method update to deal\userfield entity --- src/classes/crm/deal/userfield.php | 160 ++++++++++++++++++----------- 1 file changed, 99 insertions(+), 61 deletions(-) diff --git a/src/classes/crm/deal/userfield.php b/src/classes/crm/deal/userfield.php index 66db9f55..eb6ecc11 100644 --- a/src/classes/crm/deal/userfield.php +++ b/src/classes/crm/deal/userfield.php @@ -1,6 +1,7 @@ client->call( - 'crm.deal.userfield.list', - array( - 'order' => $order, - 'filter'=> $filter - ) - ); - return $fullResult; - } + /** + * Get list of user fields items. + * + * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_userfield_list.php + * + * @param array $order - order of task items + * @param array $filter - filter array + * + * @return array + */ + public function getList($order = array(), $filter = array()) + { + $fullResult = $this->client->call( + 'crm.deal.userfield.list', + array( + 'order' => $order, + 'filter' => $filter, + ) + ); + + return $fullResult; + } + + /** + * Get item userfield + * + * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_userfield_get.php + * + * @param integer $userfieldId - deal userfield id + * + * @return array + */ + public function get($userfieldId) + { + $fullResult = $this->client->call( + 'crm.deal.userfield.get', + array('id' => $userfieldId) + ); + + return $fullResult; + } + + /** + * Delete userfield + * + * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_userfield_delete.php + * + * @param integer $userfieldId - deal userfield id + * + * @return array + */ + public function delete($userfieldId) + { + $fullResult = $this->client->call( + 'crm.deal.userfield.delete', + array('id' => $userfieldId) + ); + + return $fullResult; + } + + /** + * Add a new userfield to deal + * + * @param array $fields array of fields + * + * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_userfield_add.php + * @return array + */ + public function add($fields = array()) + { + $fullResult = $this->client->call( + 'crm.deal.userfield.add', + array('fields' => $fields) + ); - /** - * Get item userfield - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_userfield_get.php - * @param integer $userfieldId - deal userfield id - * @return array - */ - public function get($userfieldId) - { - $fullResult = $this->client->call( - 'crm.deal.userfield.get', - array('id' => $userfieldId) - ); - return $fullResult; - } + return $fullResult; + } - /** - * Delete userfield - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_userfield_delete.php - * @param integer $userfieldId - deal userfield id - * @return array - */ - public function delete($userfieldId) - { - $fullResult = $this->client->call( - 'crm.deal.userfield.delete', - array('id' => $userfieldId) - ); - return $fullResult; - } + /** + * Add a new userfield to deal + * + * @param int $userfieldId deal userfield id + * @param array $fields array of fields + * + * @link https://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_userfield_update.php + * @return array + */ + public function update($userfieldId, $fields = array()) + { + $fullResult = $this->client->call( + 'crm.deal.userfield.update', + array( + 'id' => $userfieldId, + 'fields' => $fields, + ) + ); - /** - * Add a new userfield to deal - * @param array $fields array of fields - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_userfield_add.php - * @return array - */ - public function add($fields = array()) - { - $fullResult = $this->client->call( - 'crm.deal.userfield.add', - array('fields' => $fields) - ); - return $fullResult; - } -} + return $fullResult; + } +} \ No newline at end of file From 3c8a103428abe41b6ebb07827445edd29510274c Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Tue, 24 Oct 2017 23:37:28 +0300 Subject: [PATCH 106/647] issue#77 add Product\Property support --- src/classes/crm/product/property.php | 104 +++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 src/classes/crm/product/property.php diff --git a/src/classes/crm/product/property.php b/src/classes/crm/product/property.php new file mode 100644 index 00000000..415091bf --- /dev/null +++ b/src/classes/crm/product/property.php @@ -0,0 +1,104 @@ +client->call( + 'crm.product.property.get', + array('id' => $productPropertyId) + ); + + return $fullResult; + } + + /** + * get product property list + * + * @link https://dev.1c-bitrix.ru/rest_help/crm/products/crm_product_property_list.php + * + * @param array $order + * @param array $filter + * + * @return array + * @throws Bitrix24Exception + */ + public function getList($order = array(), $filter = array()) + { + $fullResult = $this->client->call( + 'crm.product.property.list', + array( + 'order' => $order, + 'filter' => $filter, + ) + ); + + return $fullResult; + } + + /** + * add product property + * + * @link https://dev.1c-bitrix.ru/rest_help/crm/products/crm_product_property_list.php + * + * @param array $fields + * + * @return array + * @throws Bitrix24Exception + */ + public function add(array $fields) + { + $fullResult = $this->client->call( + 'crm.product.property.add', + array( + 'fields' => $fields, + ) + ); + + return $fullResult; + } + + /** + * update product property + * + * @link https://dev.1c-bitrix.ru/rest_help/crm/products/crm_product_property_update.php + * + * @param int $productPropertyId + * @param array $fields + * + * @return array + * @throws Bitrix24Exception + */ + public function update($productPropertyId, array $fields) + { + $fullResult = $this->client->call( + 'crm.product.property.add', + array( + 'id' => $productPropertyId, + 'fields' => $fields, + ) + ); + + return $fullResult; + } +} \ No newline at end of file From 5a672c7a2046f5b7fe05e463768d3937b68dd589 Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Mon, 30 Oct 2017 01:28:15 +0300 Subject: [PATCH 107/647] issue#79 Add support crm.product.property.types --- src/classes/crm/product/property.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/classes/crm/product/property.php b/src/classes/crm/product/property.php index 415091bf..01262022 100644 --- a/src/classes/crm/product/property.php +++ b/src/classes/crm/product/property.php @@ -101,4 +101,16 @@ public function update($productPropertyId, array $fields) return $fullResult; } + + /** + * get property types + * + * @link https://dev.1c-bitrix.ru/rest_help/crm/products/crm_product_property_types.php + * @return array + * @throws Bitrix24Exception + */ + public function getTypes() + { + return $this->client->call('crm.product.property.types'); + } } \ No newline at end of file From 82eac8b690936d78ac24ff66c612a7611e11df20 Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Tue, 31 Oct 2017 00:04:28 +0300 Subject: [PATCH 108/647] issue#82 add support method crm.product.delete --- src/classes/crm/product/product.php | 35 +++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/classes/crm/product/product.php b/src/classes/crm/product/product.php index 1563def8..bef41fdf 100644 --- a/src/classes/crm/product/product.php +++ b/src/classes/crm/product/product.php @@ -9,11 +9,14 @@ class Product extends Bitrix24Entity /** * Get list of product items. + * * @link http://dev.1c-bitrix.ru/rest_help/crm/products/crm_product_list.php + * * @param array $order - order of items * @param array $filter - filter array * @param array $select - array of columns to select * @param integer $start - entity number to start from (usually returned in 'next' field of previous 'crm.product.list' API call) + * * @return array */ public function getList($order = array(), $filter = array(), $select = array(), $start = 0) @@ -24,16 +27,20 @@ public function getList($order = array(), $filter = array(), $select = array(), 'order' => $order, 'filter' => $filter, 'select' => $select, - 'start' => $start + 'start' => $start, ) ); + return $fullResult; } /** * get product by id + * * @link http://dev.1c-bitrix.ru/rest_help/crm/products/crm_product_get.php + * * @param integer $productId - product item identifier + * * @return array */ public function get($productId) @@ -42,19 +49,40 @@ public function get($productId) 'crm.product.get', array('id' => $productId) ); + + return $fullResult; + } + + /** + * delete product by id + * + * @link https://dev.1c-bitrix.ru/rest_help/crm/products/crm_product_delete.php + * + * @param integer $productId - product item identifier + * + * @return array + */ + public function delete($productId) + { + $fullResult = $this->client->call( + 'crm.product.delete', + array('id' => $productId) + ); + return $fullResult; } /** * @param $productId * @param array $arFields + * * @return array */ public function update($productId, array $arFields) { return $this->client->call('crm.product.update', array( 'id' => $productId, - 'fields' => $arFields + 'fields' => $arFields, )); } @@ -62,7 +90,9 @@ public function update($productId, array $arFields) * add new product * * @link https://dev.1c-bitrix.ru/rest_help/crm/products/crm_product_add.php + * * @param $arNewProduct + * * @return array */ public function add($arNewProduct) @@ -71,6 +101,7 @@ public function add($arNewProduct) 'crm.product.add', array('fields' => $arNewProduct) ); + return $fullResult; } } From c4cfd604490d23d7f16873c15b373490b50b3768 Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Tue, 31 Oct 2017 00:14:08 +0300 Subject: [PATCH 109/647] issue#84 Add support method crm.product.fields --- src/classes/crm/product/product.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/classes/crm/product/product.php b/src/classes/crm/product/product.php index bef41fdf..d3e75852 100644 --- a/src/classes/crm/product/product.php +++ b/src/classes/crm/product/product.php @@ -34,6 +34,20 @@ public function getList($order = array(), $filter = array(), $select = array(), return $fullResult; } + /** + * get list of product fields with description + * + * @link https://dev.1c-bitrix.ru/rest_help/crm/products/crm_product_fields.php + * + * @return array + */ + public function fields() + { + return $this->client->call( + 'crm.product.fields' + ); + } + /** * get product by id * From 496ba469cc282dffae18daaa6aca0c26299e8a35 Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Tue, 31 Oct 2017 00:24:22 +0300 Subject: [PATCH 110/647] issue#86 add support method crm.product.property.delete --- src/classes/crm/product/property.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/classes/crm/product/property.php b/src/classes/crm/product/property.php index 01262022..ea939457 100644 --- a/src/classes/crm/product/property.php +++ b/src/classes/crm/product/property.php @@ -32,6 +32,26 @@ public function get($productPropertyId) return $fullResult; } + /** + * delete product property by id + * + * @link https://dev.1c-bitrix.ru/rest_help/crm/products/crm_product_property_delete.php + * + * @param integer $productPropertyId - product property identifier + * + * @return array + * @throws Bitrix24Exception + */ + public function delete($productPropertyId) + { + $fullResult = $this->client->call( + 'crm.product.property.delete', + array('id' => $productPropertyId) + ); + + return $fullResult; + } + /** * get product property list * From f1f8b2913df621ad3bbe07f0a675c6c677d2696e Mon Sep 17 00:00:00 2001 From: camaxtly Date: Fri, 15 Dec 2017 20:16:45 +0300 Subject: [PATCH 111/647] Add methods for \Bitrix24\CRM\Status --- src/classes/crm/status/status.php | 197 +++++++++++++++++++++++++++++- 1 file changed, 195 insertions(+), 2 deletions(-) diff --git a/src/classes/crm/status/status.php b/src/classes/crm/status/status.php index daac3df0..da25d5db 100644 --- a/src/classes/crm/status/status.php +++ b/src/classes/crm/status/status.php @@ -8,8 +8,21 @@ class Status extends Bitrix24Entity { /** * get list of dictionary fields descriptions + * * @link https://dev.1c-bitrix.ru/rest_help/crm/auxiliary/status/index.php * @return array + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException */ public function fields() { @@ -21,8 +34,21 @@ public function fields() /** * get list of dictionary types + * * @link https://dev.1c-bitrix.ru/rest_help/crm/auxiliary/status/crm_status_entity_types.php * @return array + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException */ public function entityTypes() { @@ -34,17 +60,184 @@ public function entityTypes() /** * get dictionary data + * * @link https://dev.1c-bitrix.ru/rest_help/crm/auxiliary/status/crm_status_entity_items.php + * * @param string $entityId + * * @return array + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException */ public function entityItems($entityId) { $fullResult = $this->client->call( 'crm.status.entity.items', - array( + [ 'entityId' => $entityId - ) + ] + ); + return $fullResult; + } + + /** + * @param $fields + * + * @link https://dev.1c-bitrix.ru/rest_help/crm/auxiliary/status/crm_status_add.php + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + */ + public function add($fields) + { + $fullResult = $this->client->call( + 'crm.status.add', + [ + 'fields' => $fields + ] + ); + return $fullResult; + } + + /** + * @param $id + * @param $params + * + * @link https://dev.1c-bitrix.ru/rest_help/crm/auxiliary/status/crm_status_delete.php + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + */ + public function delete($id, $params) + { + $fullResult = $this->client->call( + 'crm.status.delete', + [ + 'id' => $id, + 'params' => $params + ] + ); + return $fullResult; + } + + /** + * @param $id + * @param $fields + * + * @link https://dev.1c-bitrix.ru/rest_help/crm/auxiliary/status/crm_status_update.php + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + */ + public function update($id, $fields) + { + $fullResult = $this->client->call( + 'crm.status.update', + [ + 'id' => $id, + 'fields' => $fields + ] + ); + return $fullResult; + } + + /** + * @param $id + * + * @link https://dev.1c-bitrix.ru/rest_help/crm/auxiliary/status/crm_status_get.php + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + */ + public function get($id) + { + $fullResult = $this->client->call( + 'crm.status.get', + [ + 'id' => $id + ] + ); + return $fullResult; + } + + /** + * @param $order + * @param $filter + * + * @link https://dev.1c-bitrix.ru/rest_help/crm/auxiliary/status/crm_status_list.php + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + */ + public function getList($order, $filter) + { + $fullResult = $this->client->call( + 'crm.status.list', + [ + 'order' => $order, + 'filter' => $filter + ] ); return $fullResult; } From c3e6c251d65807a856579267994b9f4fde39a42a Mon Sep 17 00:00:00 2001 From: Uman Shield Date: Thu, 11 Jan 2018 00:34:45 +0300 Subject: [PATCH 112/647] Fix an error when trying to add a list to a task --- src/classes/task/checklistitem.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/classes/task/checklistitem.php b/src/classes/task/checklistitem.php index 34d761ea..7c6cfd4e 100644 --- a/src/classes/task/checklistitem.php +++ b/src/classes/task/checklistitem.php @@ -76,7 +76,7 @@ public function get($taskId, $checklistItemId) */ public function add($taskId, $fields) { - $result = $this->client->call('task.checklistitem.add', array($taskId, array($fields))); + $result = $this->client->call('task.checklistitem.add', array($taskId, $fields)); return $result; } @@ -166,4 +166,4 @@ public function isActionAllowed($taskId, $checklistItemId, $actionId) $result = $this->client->call('task.checklistitem.isactionallowed', array($taskId, $checklistItemId, $actionId)); return $result; } -} \ No newline at end of file +} From 40754dfdefd24aed6038c17dc225941395e5660d Mon Sep 17 00:00:00 2001 From: Oleg Prilepa Date: Sat, 3 Feb 2018 22:14:30 +0700 Subject: [PATCH 113/647] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BC=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1=8B=20=D1=81=20=D0=B6=D0=B8?= =?UTF-8?q?=D0=B2=D0=BE=D0=B9=20=D0=BB=D0=B5=D0=BD=D1=82=D0=BE=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/classes/log/blogpost.php | 46 ++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/classes/log/blogpost.php diff --git a/src/classes/log/blogpost.php b/src/classes/log/blogpost.php new file mode 100644 index 00000000..a694f6b7 --- /dev/null +++ b/src/classes/log/blogpost.php @@ -0,0 +1,46 @@ +client->call('log.blogpost.get', + array( + 'ORDER' => $order, + 'FILTER'=> $filter, + )); + return $result; + } + + /** + * @param $message + * @param $title + * @param $perm + * @link https://dev.1c-bitrix.ru/rest_help/log/log_blogpost_add.php + * @throws Bitrix24Exception + * @return array + */ + public function Add($message='', $title='', $perm=["UA"]) + { + $result = $this->client->call( + 'log.blogpost.add', + array( + 'POST_MESSAGE' => $message, + 'POST_TITLE' => $title, + 'SPERM' => $perm + ) + ); + return $result; + } +} \ No newline at end of file From 8f2772691291915a862c61f0855b79289e5460ac Mon Sep 17 00:00:00 2001 From: Oleg Prilepa Date: Sat, 3 Feb 2018 22:24:13 +0700 Subject: [PATCH 114/647] bugfix for php 5.3 --- src/classes/log/blogpost.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/classes/log/blogpost.php b/src/classes/log/blogpost.php index a694f6b7..07e8ea8b 100644 --- a/src/classes/log/blogpost.php +++ b/src/classes/log/blogpost.php @@ -31,7 +31,7 @@ public function Get($order, $filter) * @throws Bitrix24Exception * @return array */ - public function Add($message='', $title='', $perm=["UA"]) + public function Add($message='', $title='', $perm=array("UA")) { $result = $this->client->call( 'log.blogpost.add', From 608cd140d8e788057d033b1c10ce765dfe3cfb3e Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 17 Feb 2018 20:35:47 +0300 Subject: [PATCH 115/647] task#96 add userfield type support --- src/classes/userfieldtype/UserfieldType.php | 126 ++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 src/classes/userfieldtype/UserfieldType.php diff --git a/src/classes/userfieldtype/UserfieldType.php b/src/classes/userfieldtype/UserfieldType.php new file mode 100644 index 00000000..b5362bc2 --- /dev/null +++ b/src/classes/userfieldtype/UserfieldType.php @@ -0,0 +1,126 @@ +client->call('userfieldtype.add', array( + 'USER_TYPE_ID' => $userTypeId, + 'HANDLER' => $handlerUrl, + 'TITLE' => $title, + 'DESCRIPTION' => $description, + )); + } + + /** + * update userfield type + * + * @param $userTypeId + * @param $handlerUrl + * @param $title + * @param $description + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + */ + public function update($userTypeId, $handlerUrl, $title, $description) + { + return $this->client->call('userfieldtype.update', array( + 'USER_TYPE_ID' => $userTypeId, + 'HANDLER' => $handlerUrl, + 'TITLE' => $title, + 'DESCRIPTION' => $description, + )); + } + + /** + * delete userfield type + * + * @param $userTypeId + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + */ + public function delete($userTypeId) + { + return $this->client->call('userfieldtype.delete', array( + 'USER_TYPE_ID' => $userTypeId, + )); + } + + /** + * get list of userfield type + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + */ + public function getList() + { + return $this->client->call('userfieldtype.list'); + } +} \ No newline at end of file From 0593be913734c0bb0169bf557f5ef9d45e2945b6 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 17 Feb 2018 20:37:26 +0300 Subject: [PATCH 116/647] task#96 add placements --- src/presets/placement/Placement.php | 33 +++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/presets/placement/Placement.php b/src/presets/placement/Placement.php index d00cfdda..3b7bf4b3 100644 --- a/src/presets/placement/Placement.php +++ b/src/presets/placement/Placement.php @@ -4,6 +4,7 @@ /** * Class Fields + * * @package Bitrix24\Presets\Placement */ class Placement @@ -40,4 +41,36 @@ class Placement * @var string */ const CRM_ACTIVITY_LIST_MENU = 'CRM_ACTIVITY_LIST_MENU'; + /** + * @var string + */ + const CRM_LEAD_DETAIL_TAB = 'CRM_LEAD_DETAIL_TAB'; + /** + * @var string + */ + const CRM_DEAL_DETAIL_TAB = 'CRM_DEAL_DETAIL_TAB'; + /** + * @var string + */ + const CRM_CONTACT_DETAIL_TAB = 'CRM_CONTACT_DETAIL_TAB'; + /** + * @var string + */ + const CRM_COMPANY_DETAIL_TAB = 'CRM_COMPANY_DETAIL_TAB'; + /** + * @var string + */ + const CRM_LEAD_DETAIL_ACTIVITY = 'CRM_LEAD_DETAIL_ACTIVITY'; + /** + * @var string + */ + const CRM_DEAL_DETAIL_ACTIVITY = 'CRM_DEAL_DETAIL_ACTIVITY'; + /** + * @var string + */ + const CRM_CONTACT_DETAIL_ACTIVITY = 'CRM_CONTACT_DETAIL_ACTIVITY'; + /** + * @var string + */ + const CRM_COMPANY_DETAIL_ACTIVITY = 'CRM_COMPANY_DETAIL_ACTIVITY'; } \ No newline at end of file From c640d3fa8e8fc4b64050ac0a00ee6ca921025e39 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 18 Feb 2018 10:36:51 +0300 Subject: [PATCH 117/647] task#96 add presents for request timing information --- CHANGELOG.md | 17 ++++++++++++++++ src/presets/timing.php | 44 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 src/presets/timing.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 829d6230..35f5599a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,21 @@ # bitrix24-php-sdk change log +## 0.6.0 (18.02.2018) +* add presets for request timing information +* add all methods for sonetgroup +* add method `crm.contact.userfield.update` +* add activities methods +* add exception `Bitrix24PortalRenamedException` +* add a pair of fields for the Lead +* add requisite support +* add method update to deal\userfield entity +* add `Product\Property` support +* add method `crm.product.delete` +* add method `crm.product.fields` +* add method `crm.product.property.types` +* add method `crm.product.property.delete` +* add methods for `\Bitrix24\CRM\Status` +* add new placement presets for detail page + ## 0.5.4 (8.07.2017) * add Callback for expired token. Fix pullrequest#63 by valga * add method `update` in class `Bitrix24\CRM\Product` diff --git a/src/presets/timing.php b/src/presets/timing.php new file mode 100644 index 00000000..61f2b806 --- /dev/null +++ b/src/presets/timing.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24\Presets; + +/** + * Class Timing + * + * @package Bitrix24\Presets + */ +class Timing +{ + /** + * @var string + */ + const START = 'start'; + /** + * @var string + */ + const FINISH = 'finish'; + /** + * @var string + */ + const DURATION = 'duration'; + /** + * @var string + */ + const PROCESSING = 'processing'; + /** + * @var string + */ + const DATE_START = 'date_start'; + /** + * @var string + */ + const DATE_FINISH = 'date_finish'; +} \ No newline at end of file From 2c7ec6d7b34324af657daa8e7d8fc23a792ba1f2 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 18 Feb 2018 13:10:58 +0300 Subject: [PATCH 118/647] task#96 add support for face tracker entity --- CHANGELOG.md | 1 + src/classes/facetracker/client.php | 58 ++++++++++++++++++++++ src/classes/facetracker/user.php | 79 ++++++++++++++++++++++++++++++ 3 files changed, 138 insertions(+) create mode 100644 src/classes/facetracker/client.php create mode 100644 src/classes/facetracker/user.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 35f5599a..754b90cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # bitrix24-php-sdk change log ## 0.6.0 (18.02.2018) +* add support for `FaceTracker` entity * add presets for request timing information * add all methods for sonetgroup * add method `crm.contact.userfield.update` diff --git a/src/classes/facetracker/client.php b/src/classes/facetracker/client.php new file mode 100644 index 00000000..e15ce5ed --- /dev/null +++ b/src/classes/facetracker/client.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24\FaceTracker; + +use Bitrix24\Bitrix24Entity; +use Bitrix24\Exceptions\Bitrix24Exception; + +/** + * Class Client + * + * @package Bitrix24\FaceTracker + */ +class Client extends Bitrix24Entity +{ + /** + * add client face to client library + * + * @see https://dev.1c-bitrix.ru/rest_help/faceid/face_client_add.php + * + * @param $clientPhoto string client base64 encoding photo + * + * @return array + * @throws Bitrix24Exception + */ + public function add($clientPhoto) + { + return $this->client->call('face.client.add', array('PHOTO' => $clientPhoto)); + } + + /** + * find client face in client gallery + * + * @see https://dev.1c-bitrix.ru/rest_help/faceid/face_client_identify.php + * + * @param $clientPhoto string client base64 encoding photo + * @param $isForceAdd + * + * @return array + * @throws Bitrix24Exception + */ + public function identify($clientPhoto, $isForceAdd) + { + return $this->client->call('face.client.identify', + array( + 'PHOTO' => $clientPhoto, + 'FORCE_ADD' => $isForceAdd === true ? 'Y' : 'N', + ) + ); + } +} \ No newline at end of file diff --git a/src/classes/facetracker/user.php b/src/classes/facetracker/user.php new file mode 100644 index 00000000..0a5f4f12 --- /dev/null +++ b/src/classes/facetracker/user.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24\FaceTracker; + +use Bitrix24\Bitrix24Entity; +use Bitrix24\Exceptions\Bitrix24Exception; + +/** + * Class User + * + * @package Bitrix24\FaceTracker + */ +class User extends Bitrix24Entity +{ + /** + * add user face to client library + * + * @param $userId int user identifier + * @param $userPhoto string client base64 encoding photo + * + * @return array + * @throws Bitrix24Exception + */ + public function add($userId, $userPhoto) + { + return $this->client->call('face.user.add', + array( + 'PHOTO' => $userPhoto, + 'USER_ID' => $userId, + ) + ); + } + + /** + * find user face in user gallery + * + * @see https://dev.1c-bitrix.ru/rest_help/faceid/face_user_identify.php + * + * @param $clientPhoto string client base64 encoding photo + * + * @return array + * @throws Bitrix24Exception + */ + public function identify($clientPhoto) + { + return $this->client->call('face.user.identify', + array( + 'PHOTO' => $clientPhoto, + ) + ); + } + + /** + * delete face from user gallery + * + * @see https://dev.1c-bitrix.ru/rest_help/faceid/face_user_delete.php + * + * @param $faceId + * + * @return array + * @throws Bitrix24Exception + */ + public function delete($faceId) + { + return $this->client->call('face.user.delete', + array( + 'FACE_ID' => $faceId, + ) + ); + } +} \ No newline at end of file From 0082cd7e5900ff86c205dd9be5a15ddb26cc4ea6 Mon Sep 17 00:00:00 2001 From: camaxtly Date: Sun, 18 Feb 2018 14:36:08 +0300 Subject: [PATCH 119/647] task#98 Add userfields support --- src/classes/crm/invoice/invoice.php | 119 +++++++++++++++--- src/classes/crm/invoice/status.php | 50 ++++++-- src/classes/crm/invoice/userfield.php | 172 ++++++++++++++++++++++++++ 3 files changed, 313 insertions(+), 28 deletions(-) create mode 100644 src/classes/crm/invoice/userfield.php diff --git a/src/classes/crm/invoice/invoice.php b/src/classes/crm/invoice/invoice.php index 8266cb7a..b7736fe7 100644 --- a/src/classes/crm/invoice/invoice.php +++ b/src/classes/crm/invoice/invoice.php @@ -19,22 +19,37 @@ class Invoice extends Bitrix24Entity /** * Get list of lead items. + * * @link http://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_invoice_list.php - * @param array $order - order of task items - * @param array $filter - filter array - * @param array $select - array of collumns to select - * @param integer $start - entity number to start from (usually returned in 'next' field of previous 'crm.invoice.list' API call) + * + * @param array $order - order of task items + * @param array $filter - filter array + * @param array $select - array of collumns to select + * @param integer $start - entity number to start from (usually returned in 'next' field of previous 'crm.invoice.list' API call) + * * @return array + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException */ public function getList($order = array(), $filter = array(), $select = array(), $start = 0) { $fullResult = $this->client->call( 'crm.invoice.list', array( - 'order' => $order, - 'filter'=> $filter, - 'select'=> $select, - 'start' => $start + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $start ) ); return $fullResult; @@ -42,10 +57,23 @@ public function getList($order = array(), $filter = array(), $select = array(), /** * get invoice by id - * @var $invoiceId integer invoice identifier + * * @link http://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_invoice_get.php + * @var $invoiceId integer invoice identifier * @return array - */ + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException +*/ public function get($invoiceId) { $fullResult = $this->client->call( @@ -57,10 +85,23 @@ public function get($invoiceId) /** * delete invoice by id - * @var $invoiceId integer invoice identifier + * * @link http://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_invoice_delete.php + * @var $invoiceId integer invoice identifier * @return array - */ + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException +*/ public function delete($invoiceId) { $fullResult = $this->client->call( @@ -72,10 +113,24 @@ public function delete($invoiceId) /** * Add a new invoice to CRM + * * @param array $fields array of fields - * @link http://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_invoice_add.php + * * @return array - */ + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @link http://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_invoice_add.php +*/ public function add($fields = array()) { $fullResult = $this->client->call( @@ -87,11 +142,26 @@ public function add($fields = array()) /** * update invoice by id - * @var $invoiceId integer invoice identifier - * @var $invoiceFields array invoice fields to update + * * @link http://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_invoice_update.php + * + * @param $invoiceId + * @param $invoiceFields + * * @return array - */ + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException +*/ public function update($invoiceId, $invoiceFields) { $fullResult = $this->client->call( @@ -106,9 +176,22 @@ public function update($invoiceId, $invoiceFields) /** * get list of invoice fields with description + * * @link http://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_invoice_fields.php * @return array - */ + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException +*/ public function fields() { $fullResult = $this->client->call( diff --git a/src/classes/crm/invoice/status.php b/src/classes/crm/invoice/status.php index 7cf4db20..5b3c116c 100644 --- a/src/classes/crm/invoice/status.php +++ b/src/classes/crm/invoice/status.php @@ -6,22 +6,37 @@ class Status extends Bitrix24Entity { /** * Get list of Invoice.Status items. + * * @link http://dev.1c-bitrix.ru/rest_help/crm/invoice_status/crm_invoice_status_list.php - * @param array $order - order of items - * @param array $filter - filter array - * @param array $select - array of columns to select - * @param integer $start - entity number to start from (usually returned in 'next' field of previous 'crm.invoice.status.list' API call) + * + * @param array $order - order of items + * @param array $filter - filter array + * @param array $select - array of columns to select + * @param integer $start - entity number to start from (usually returned in 'next' field of previous 'crm.invoice.status.list' API call) + * * @return array + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException */ public function getList($order = array(), $filter = array(), $select = array(), $start = 0) { $fullResult = $this->client->call( 'crm.invoice.status.list', array( - 'order' => $order, - 'filter'=> $filter, - 'select'=> $select, - 'start' => $start + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $start ) ); return $fullResult; @@ -29,10 +44,25 @@ public function getList($order = array(), $filter = array(), $select = array(), /** * get by id + * * @link http://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_invoice_status_get.php - * @param integer $invoiceStatusId - invoice status identifier + * + * @param integer $invoiceStatusId - invoice status identifier + * * @return array - */ + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException +*/ public function get($invoiceStatusId) { $fullResult = $this->client->call( diff --git a/src/classes/crm/invoice/userfield.php b/src/classes/crm/invoice/userfield.php new file mode 100644 index 00000000..d4f08bd2 --- /dev/null +++ b/src/classes/crm/invoice/userfield.php @@ -0,0 +1,172 @@ +client->call( + 'crm.invoice.userfield.list', + array( + 'order' => $order, + 'filter' => $filter, + ) + ); + + return $fullResult; + } + + /** + * Get item userfield + * + * @link https://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_invoice_userfield_get.php + * + * @param integer $userfieldId - invoice userfield id + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + */ + public function get($userfieldId) + { + $fullResult = $this->client->call( + 'crm.invoice.userfield.get', + array('id' => $userfieldId) + ); + + return $fullResult; + } + + /** + * Delete userfield + * + * @link https://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_invoice_userfield_delete.php + * + * @param integer $userfieldId - invoice userfield id + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + */ + public function delete($userfieldId) + { + $fullResult = $this->client->call( + 'crm.invoice.userfield.delete', + array('id' => $userfieldId) + ); + + return $fullResult; + } + + /** + * Add a new userfield to invoice + * + * @param array $fields array of fields + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @link https://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_invoice_userfield_add.php + */ + public function add($fields = array()) + { + $fullResult = $this->client->call( + 'crm.invoice.userfield.add', + array('fields' => $fields) + ); + + return $fullResult; + } + + /** + * Update a new userfield to invoice + * + * @param int $userfieldId invoice userfield id + * @param array $fields array of fields + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @link https://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_invoice_userfield_update.php + */ + public function update($userfieldId, $fields = array()) + { + $fullResult = $this->client->call( + 'crm.invoice.userfield.update', + array( + 'id' => $userfieldId, + 'fields' => $fields, + ) + ); + + return $fullResult; + } +} \ No newline at end of file From d45008735bc5f0467ec506aa105e972b297d25db Mon Sep 17 00:00:00 2001 From: camaxtly Date: Sun, 18 Feb 2018 15:07:33 +0300 Subject: [PATCH 120/647] task#98 Add paysystem adm persontype support --- src/classes/crm/invoice/paysystem.php | 75 ++++++++++++++++++++++++++ src/classes/crm/invoice/persontype.php | 75 ++++++++++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 src/classes/crm/invoice/paysystem.php create mode 100644 src/classes/crm/invoice/persontype.php diff --git a/src/classes/crm/invoice/paysystem.php b/src/classes/crm/invoice/paysystem.php new file mode 100644 index 00000000..b3d8927b --- /dev/null +++ b/src/classes/crm/invoice/paysystem.php @@ -0,0 +1,75 @@ +client->call( + 'crm.paysystem.list', + array( + 'order' => $order, + 'filter' => $filter, + ) + ); + + return $fullResult; + } + + + /** + * @link https://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_paysystem_fields.php + * + * @return array + * + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * + */ + public function fields() + { + $fullResult = $this->client->call( + 'crm.paysystem.fields', + array() + ); + + return $fullResult; + } +} \ No newline at end of file diff --git a/src/classes/crm/invoice/persontype.php b/src/classes/crm/invoice/persontype.php new file mode 100644 index 00000000..a6090ffb --- /dev/null +++ b/src/classes/crm/invoice/persontype.php @@ -0,0 +1,75 @@ +client->call( + 'crm.persontype.list', + array( + 'order' => $order, + 'filter' => $filter, + ) + ); + + return $fullResult; + } + + + /** + * @link https://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_persontype_fields.php + * + * @return array + * + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * + */ + public function fields() + { + $fullResult = $this->client->call( + 'crm.persontype.fields', + array() + ); + + return $fullResult; + } +} \ No newline at end of file From b7f0a16e912862b1b26841b0734f0ae972763e13 Mon Sep 17 00:00:00 2001 From: camaxtly Date: Sun, 25 Mar 2018 23:53:36 +0300 Subject: [PATCH 121/647] ProductSection support --- .../crm/productsection/productsection.php | 197 ++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 src/classes/crm/productsection/productsection.php diff --git a/src/classes/crm/productsection/productsection.php b/src/classes/crm/productsection/productsection.php new file mode 100644 index 00000000..7fe8e199 --- /dev/null +++ b/src/classes/crm/productsection/productsection.php @@ -0,0 +1,197 @@ +client->call( + 'crm.productsection.list', + array( + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $start, + ) + ); + + return $fullResult; + } + + /** + * get list of product fields with description + * + * @link https://dev.1c-bitrix.ru/rest_help/crm/product_section/crm_productsection_fields.php + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + */ + public function fields() + { + return $this->client->call( + 'crm.productsection.fields' + ); + } + + /** + * get product by id + * + * @link https://dev.1c-bitrix.ru/rest_help/crm/product_section/crm_productsection_get.php + * + * @param integer $id - product item identifier + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + */ + public function get($id) + { + $fullResult = $this->client->call( + 'crm.productsection.get', + array('id' => $id) + ); + + return $fullResult; + } + + /** + * delete product by id + * + * @link https://dev.1c-bitrix.ru/rest_help/crm/product_section/crm_productsection_delete.php + * + * @param integer $id - product item identifier + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + */ + public function delete($id) + { + $fullResult = $this->client->call( + 'crm.productsection.delete', + array('id' => $id) + ); + + return $fullResult; + } + + /** + * @link https://dev.1c-bitrix.ru/rest_help/crm/product_section/crm_productsection_update.php + * + * @param $id + * @param array $arFields + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + */ + public function update($id, array $arFields) + { + return $this->client->call('crm.productsection.update', array( + 'id' => $id, + 'fields' => $arFields, + )); + } + + /** + * @link https://dev.1c-bitrix.ru/rest_help/crm/product_section/crm_productsection_add.php + * + * @param $arProductSection + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + */ + public function add($arProductSection) + { + $fullResult = $this->client->call( + 'crm.productsection.add', + array('fields' => $arProductSection) + ); + + return $fullResult; + } +} + + + From a199411461fc8f696bbfbcd2541b64d7e10792f0 Mon Sep 17 00:00:00 2001 From: camaxtly Date: Sun, 25 Mar 2018 23:59:45 +0300 Subject: [PATCH 122/647] task#98 externalLink --- src/classes/crm/invoice/invoice.php | 30 +++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/classes/crm/invoice/invoice.php b/src/classes/crm/invoice/invoice.php index b7736fe7..ff024aba 100644 --- a/src/classes/crm/invoice/invoice.php +++ b/src/classes/crm/invoice/invoice.php @@ -199,4 +199,34 @@ public function fields() ); return $fullResult; } + + /** + * get external link for invoice + * + * @param $id + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + */ + public function getExternalLink($id) + { + $fullResult = $this->client->call( + 'crm.invoice.getexternallink', + array( + 'id' => $id + ) + ); + return $fullResult; + } } From af3b5fb9ac61ac9385c8ea450851665f9067c5be Mon Sep 17 00:00:00 2001 From: MrDeff Date: Tue, 27 Mar 2018 12:56:53 +0700 Subject: [PATCH 123/647] fix getList --- src/classes/task/commentitem.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/classes/task/commentitem.php b/src/classes/task/commentitem.php index b16b123d..03867961 100644 --- a/src/classes/task/commentitem.php +++ b/src/classes/task/commentitem.php @@ -30,12 +30,7 @@ public function getManifest() */ public function getList($taskId, $order, $filter) { - $result = $this->client->call('task.commentitem.getmanifest', - array( - 'TASKID' => $taskId, - 'ORDER' => $order, - 'FILTER'=> $filter - )); + $result = $this->client->call('task.commentitem.getlist', array($taskId, $order, $filter)); return $result; } From 3f0b6f619d8bb62af8c92ebc8fe2803827908212 Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 11 Apr 2018 01:54:38 +0300 Subject: [PATCH 124/647] task#102 add crm-robots support --- src/classes/bizproc/Robot.php | 112 ++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 src/classes/bizproc/Robot.php diff --git a/src/classes/bizproc/Robot.php b/src/classes/bizproc/Robot.php new file mode 100644 index 00000000..b2b739ae --- /dev/null +++ b/src/classes/bizproc/Robot.php @@ -0,0 +1,112 @@ +client->call('bizproc.activity.add', + array( + 'CODE' => $code, + 'HANDLER' => $handler, + 'AUTH_USER_ID' => $userId, + 'NAME' => $arName, + 'PROPERTIES' => $arProps, + )); + + return $arResult['result']; + } + + /** + * delete activity + * + * @param $code string + * + * @see https://dev.1c-bitrix.ru/rest_help/bizproc/bizproc_robot/robotdelete.php + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + */ + public function delete($code) + { + $arResult = $this->client->call('bizproc.robot.delete', + array( + 'code' => $code, + ) + ); + + return $arResult['result']; + } + + /** + * get list of robots + * + * @see https://dev.1c-bitrix.ru/rest_help/bizproc/bizproc_robot/robotlist.php + * + * @return mixed + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + */ + public function getList() + { + $arResult = $this->client->call('bizproc.robot.list', + array() + ); + + return $arResult['result']; + } +} \ No newline at end of file From d54bd6e1ca8a7b099b33f8f5b9cec4a0c3026b94 Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 25 Apr 2018 15:54:51 +0800 Subject: [PATCH 125/647] the ability to disable SSL verify This capability is needed on servers with self-signed certificates for development --- src/bitrix24.php | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/bitrix24.php b/src/bitrix24.php index 1e547d32..18567b6c 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -141,6 +141,12 @@ class Bitrix24 implements iBitrix24 */ protected $_onExpiredToken; + /** + * @var bool ssl verify for checking CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST + */ + protected $sslVerify = true; + + /** * Create a object to work with Bitrix24 REST API service * @@ -443,6 +449,22 @@ public function setDomain($domain) return true; } + /** + * disable of checking CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST + */ + public function setDisabledSslVerify () + { + $this->sslVerify = false; + } + + /** + * enable of checking CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST + */ + public function setEnabledSslVerify () + { + $this->sslVerify = true; + } + /** * Execute a request API to Bitrix24 using cURL * @@ -481,6 +503,12 @@ protected function executeRequest($url, array $additionalParameters = array()) CURLOPT_POSTFIELDS => http_build_query($additionalParameters), CURLOPT_URL => $url ); + + if (!$this->sslVerify) + { + $curlOptions[CURLOPT_SSL_VERIFYPEER] = 0; + $curlOptions[CURLOPT_SSL_VERIFYHOST] = 0; + } if (is_array($this->customCurlOptions)) { foreach ($this->customCurlOptions as $customCurlOptionKey => $customCurlOptionValue) { From 29ef51c0f0cdb751e7f7bbe12094e48ec213bb55 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 28 Apr 2018 00:07:28 +0300 Subject: [PATCH 126/647] task#108 fix method bizproc.robot.add --- src/classes/bizproc/Robot.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/classes/bizproc/Robot.php b/src/classes/bizproc/Robot.php index b2b739ae..12220583 100644 --- a/src/classes/bizproc/Robot.php +++ b/src/classes/bizproc/Robot.php @@ -39,7 +39,7 @@ class Robot extends Bitrix24Entity */ public function add($code, $handler, $userId, $arName, $arProps) { - $arResult = $this->client->call('bizproc.activity.add', + $arResult = $this->client->call('bizproc.robot.add', array( 'CODE' => $code, 'HANDLER' => $handler, From 6a232d7874996ec6d855746a544f26a8611a1143 Mon Sep 17 00:00:00 2001 From: GSU Date: Fri, 25 May 2018 23:19:02 +1000 Subject: [PATCH 127/647] resolve problem https://github.com/mesilov/bitrix24-php-sdk/issues/35 --- src/classes/im/im.php | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/classes/im/im.php b/src/classes/im/im.php index 2a077d1e..5be2964d 100644 --- a/src/classes/im/im.php +++ b/src/classes/im/im.php @@ -45,4 +45,47 @@ public function notify($userId, $message, $notifyType = B24ImFields::NOTIFY_TYPE ); return $fullResult; } + + + /** + * add a message to private/public group chats + * @param int $chatId + * @param $message + * @param string $system + * @param string $userId + * @return array + */ + public function messageAdd($chatId = 1, $message, $system = 'N', $userId = '') + { + if(is_null($chatId) && empty($userId)) + { + throw new Bitrix24Exception('chat id is null and user id is empty'); + } + elseif(is_null($message)) + { + throw new Bitrix24Exception('message is null'); + } + elseif(!in_array($system, array("N", "Y"), true)) + { + throw new Bitrix24Exception('unknown system'); + } + + $arAdditionalParameters = array( + 'message' => $message, + 'system' => $system + ); + + if (!empty($userId)) { + $arAdditionalParameters['user_id'] = $userId; + } else { + $arAdditionalParameters['chat_id'] = $chatId; + } + + $fullResult = $this->client->call( + 'im.message.add', + $arAdditionalParameters + ); + return $fullResult; + } + } \ No newline at end of file From 5cb6ce930ab95c3730cd6b689b2fd2bdb22c228a Mon Sep 17 00:00:00 2001 From: Ievgenii Gardysh Date: Fri, 1 Jun 2018 14:40:55 +0300 Subject: [PATCH 128/647] * added offset parameter to get user function --- src/classes/user/user.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/classes/user/user.php b/src/classes/user/user.php index c9be1b37..5b43eb11 100644 --- a/src/classes/user/user.php +++ b/src/classes/user/user.php @@ -50,13 +50,14 @@ public function fields() * @param $FILTER - list of fields user entity to filter result * @return array */ - public function get($SORT, $ORDER, $FILTER) + public function get($SORT, $ORDER, $FILTER, $OFFSET) { $result = $this->client->call('user.get', array( 'SORT' => $SORT, 'ORDER' => $ORDER, - 'FILTER'=> $FILTER) + 'FILTER'=> $FILTER, + 'start' => $OFFSET) ); return $result; } From ee34d4ddcc29f5da817424d51da18a9b817bdafe Mon Sep 17 00:00:00 2001 From: Ievgenii Gardysh Date: Mon, 11 Jun 2018 01:31:58 +0300 Subject: [PATCH 129/647] + Lead class: added class to work with products (get/set of lead productrows) --- src/classes/crm/lead/productrows.php | 45 ++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 src/classes/crm/lead/productrows.php diff --git a/src/classes/crm/lead/productrows.php b/src/classes/crm/lead/productrows.php new file mode 100644 index 00000000..54b8c57e --- /dev/null +++ b/src/classes/crm/lead/productrows.php @@ -0,0 +1,45 @@ +client->call( + 'crm.lead.productrows.get', + array( + 'id' => $id + ) + ); + return $fullResult; + } + + /** + * Set lead products. + * @link https://dev.1c-bitrix.ru/rest_help/crm/leads/crm_lead_productrows_set.php + * @param int $id - lead id + * @param array $rows - products data + * @return array + */ + public function set($id, $rows) + { + $fullResult = $this->client->call( + 'crm.lead.productrows.set', + array( + 'id' => $id, + 'rows' => $rows + ) + ); + return $fullResult; + } +} From 5454d09f2a0a1042174f8cd64e7056564781b2f3 Mon Sep 17 00:00:00 2001 From: Ievgenii Gardysh Date: Wed, 20 Jun 2018 18:30:11 +0300 Subject: [PATCH 130/647] * User class: "get" function: added default value to $OFFSET parameter --- src/classes/user/user.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/classes/user/user.php b/src/classes/user/user.php index 5b43eb11..83ed2d8e 100644 --- a/src/classes/user/user.php +++ b/src/classes/user/user.php @@ -50,7 +50,7 @@ public function fields() * @param $FILTER - list of fields user entity to filter result * @return array */ - public function get($SORT, $ORDER, $FILTER, $OFFSET) + public function get($SORT, $ORDER, $FILTER, $OFFSET = 0) { $result = $this->client->call('user.get', array( From 270fe89f848b0ccd4df2c3baaa53b7e096e72465 Mon Sep 17 00:00:00 2001 From: Ievgenii Gardysh Date: Fri, 13 Jul 2018 11:00:00 +0300 Subject: [PATCH 131/647] * Changed required version of PHP to avoid "Fatal error: Uncaught exception 'Bitrix24\Exceptions\Bitrix24IoException' with message 'in try[0] cURL error (code 3): No URL set!" --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index dcd28c60..8b436fcb 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ } ], "require": { - "php": ">=5.3.2", + "php": ">=5.6", "ext-json": "*", "ext-curl": "*", "psr/log": "^1.0" From c7353afda1ee4b7e8da425ddcfac8db87858893c Mon Sep 17 00:00:00 2001 From: Marat Shamshutdinov Date: Thu, 20 Sep 2018 10:43:40 +0300 Subject: [PATCH 132/647] handle api level errors in batch calls --- src/bitrix24.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/bitrix24.php b/src/bitrix24.php index 18567b6c..0894a11a 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -1035,6 +1035,13 @@ public function processBatchCalls($halt = 0, $delay = self::BATCH_DELAY) continue; } + if (isset($results['result_error'][$idx])) { + $this->handleBitrix24APILevelErrors(array( + 'error' => $results['result_error'][$idx]['error'], + 'error_description' => $results['result_error'][$idx]['error_description'], + ), $call['method'], $call['parameters']); + } + call_user_func($call['callback'], array( 'result' => isset($results['result'][$idx]) ? $results['result'][$idx] : null, 'error' => isset($results['result_error'][$idx]) ? $results['result_error'][$idx] : null, From f937db81545df87f829d2092f889d83b03522dbb Mon Sep 17 00:00:00 2001 From: Marat Shamshutdinov Date: Thu, 20 Sep 2018 10:46:22 +0300 Subject: [PATCH 133/647] exception for insufficient_scope api error --- src/bitrix24.php | 4 ++++ src/exceptions/bitrix24insufficientscope.php | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 src/exceptions/bitrix24insufficientscope.php diff --git a/src/bitrix24.php b/src/bitrix24.php index 18567b6c..aecb1d7e 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -24,6 +24,7 @@ use Bitrix24\Exceptions\Bitrix24TokenIsExpiredException; use Bitrix24\Exceptions\Bitrix24TokenIsInvalidException; use Bitrix24\Exceptions\Bitrix24WrongClientException; +use Bitrix24\Exceptions\Bitrix24InsufficientScope; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; @@ -741,6 +742,7 @@ public function setRetriesToConnectTimeout($microseconds = 1000000) * @throws Bitrix24MethodNotFoundException * @throws Bitrix24PaymentRequiredException * @throws Bitrix24PortalRenamedException + * @throws Bitrix24InsufficientScope */ protected function handleBitrix24APILevelErrors( $arRequestResult, @@ -771,6 +773,8 @@ protected function handleBitrix24APILevelErrors( throw new Bitrix24PaymentRequiredException($errorMsg); case 'NO_AUTH_FOUND': throw new Bitrix24PortalRenamedException($errorMsg); + case 'INSUFFICIENT_SCOPE': + throw new Bitrix24InsufficientScope($errorMsg); default: throw new Bitrix24ApiException($errorMsg); } diff --git a/src/exceptions/bitrix24insufficientscope.php b/src/exceptions/bitrix24insufficientscope.php new file mode 100644 index 00000000..74084906 --- /dev/null +++ b/src/exceptions/bitrix24insufficientscope.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Bitrix24\Exceptions; + +/** + * Class Bitrix24InsufficientScope + * @package Bitrix24 + */ +class Bitrix24InsufficientScope extends Bitrix24ApiException +{ +} \ No newline at end of file From 65085e7862580ba6591233799f2593dff3d08bff Mon Sep 17 00:00:00 2001 From: camaxtly Date: Wed, 24 Oct 2018 13:18:58 +0300 Subject: [PATCH 134/647] providers support --- src/classes/bizproc/Provider.php | 113 +++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 src/classes/bizproc/Provider.php diff --git a/src/classes/bizproc/Provider.php b/src/classes/bizproc/Provider.php new file mode 100644 index 00000000..21c0f745 --- /dev/null +++ b/src/classes/bizproc/Provider.php @@ -0,0 +1,113 @@ +client->call('bizproc.provider.add', + array( + 'CODE' => $code, + 'TYPE' => $type, + 'HANDLER' => $handler, + 'NAME' => $arName, + 'DESCRIPTION' => $arDescription + )); + + return $arResult['result']; + } + + /** + * delete provider + * + * @param $code string + * + * @see https://dev.1c-bitrix.ru/rest_help/bizproc/bizproc_provider/providerdelete.php + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + */ + public function delete($code) + { + $arResult = $this->client->call('bizproc.provider.delete', + array( + 'code' => $code + ) + ); + + return $arResult['result']; + } + + /** + * get list of providers + * + * @see https://dev.1c-bitrix.ru/rest_help/bizproc/bizproc_provider/providerlist.php + * + * @return mixed + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + */ + public function getList() + { + $arResult = $this->client->call('bizproc.provider.list', + array() + ); + + return $arResult['result']; + } +} \ No newline at end of file From 3aa1191f806035b511cc9c09da1d37a01bcb52cb Mon Sep 17 00:00:00 2001 From: Ievgenii Gardysh Date: Fri, 26 Oct 2018 15:21:35 +0300 Subject: [PATCH 135/647] * "Status" class: "getList" function: added $OFFSET parameter --- composer.json | 2 +- src/classes/crm/status/status.php | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 8b436fcb..dcd28c60 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ } ], "require": { - "php": ">=5.6", + "php": ">=5.3.2", "ext-json": "*", "ext-curl": "*", "psr/log": "^1.0" diff --git a/src/classes/crm/status/status.php b/src/classes/crm/status/status.php index da25d5db..a9e7c32d 100644 --- a/src/classes/crm/status/status.php +++ b/src/classes/crm/status/status.php @@ -230,13 +230,14 @@ public function get($id) * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException * @throws \Bitrix24\Exceptions\Bitrix24ApiException */ - public function getList($order, $filter) + public function getList($order, $filter, $offset = 0) { $fullResult = $this->client->call( 'crm.status.list', [ 'order' => $order, - 'filter' => $filter + 'filter' => $filter, + 'start' => $offset ] ); return $fullResult; From 65d3a849cd6c3bbd866eb06d046b96bd4c52ad47 Mon Sep 17 00:00:00 2001 From: Andrey Bolonin Date: Sat, 3 Nov 2018 16:45:16 +0200 Subject: [PATCH 136/647] Update .travis.yml --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index e512dcfa..5b0d1d16 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,9 @@ php: - 5.5 - 5.6 - 7.0 + - 7.1 + - 7.2 + - 7.3 - hhvm matrix: From aa07f6fbe6445c32ddac6a82a5205bb050c865a9 Mon Sep 17 00:00:00 2001 From: kopecny-shockworks Date: Mon, 17 Dec 2018 14:59:41 +0100 Subject: [PATCH 137/647] Fixed CRM.Company.update --- src/classes/crm/company/company.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/classes/crm/company/company.php b/src/classes/crm/company/company.php index 33dda014..ec6b09ed 100644 --- a/src/classes/crm/company/company.php +++ b/src/classes/crm/company/company.php @@ -63,8 +63,10 @@ public function update($bitrix24CompanyId, $fields = array()) { $fullResult = $this->client->call( 'crm.company.update', - array('id' => $bitrix24CompanyId), - array('fields' => $fields) + array( + 'id' => $bitrix24CompanyId, + 'fields' => $fields, + ) ); return $fullResult; } From 7dfc822fd6b68bdd0958f23d8c65b1d8e523c71a Mon Sep 17 00:00:00 2001 From: slepic Date: Mon, 17 Dec 2018 17:32:25 +0000 Subject: [PATCH 138/647] unit test for previous commit (crm.company.update fix) --- tests/src/classes/crm/company/companyTest.php | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 tests/src/classes/crm/company/companyTest.php diff --git a/tests/src/classes/crm/company/companyTest.php b/tests/src/classes/crm/company/companyTest.php new file mode 100644 index 00000000..c68842f7 --- /dev/null +++ b/tests/src/classes/crm/company/companyTest.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Bitrix24\CRM; + +use Bitrix24\CRM\Company; +use Bitrix24\Contracts\iBitrix24; + +/** + * @package Bitrix24 + */ +class CompanyTest extends \PHPUnit_Framework_TestCase +{ + public function testUpdateCallsClientWithIdAndFields() + { + $testId = \md5(\time()); + $testField = \md5($testId); + $testFields = [ + $testField => \md5($testField), + ]; + + //silly mocking in PHPUnit 4.8 + $methods = array(); + $ref = new \ReflectionClass(iBitrix24::class); + foreach ($ref->getMethods() as $method) { + $methods[] = $method->getName(); + } + $client = $this->getMockBuilder(iBitrix24::class) + ->setMethods($methods) + ->getMock(); + $client->expects($this->once()) + ->method('call') + ->with( + 'crm.company.update', + array( + 'id' => $testId, + 'fields' => $testFields, + ) + ); + + $company = new Company($client); + $company->update($testId, $testFields); + } +} From 88f57fde41d7e9cd79b567e6c17f5244b2a2f34c Mon Sep 17 00:00:00 2001 From: slepic Date: Mon, 17 Dec 2018 17:42:41 +0000 Subject: [PATCH 139/647] fixed previous commit not working in PHP < 5.5 --- tests/src/classes/crm/company/companyTest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/src/classes/crm/company/companyTest.php b/tests/src/classes/crm/company/companyTest.php index c68842f7..cef81745 100644 --- a/tests/src/classes/crm/company/companyTest.php +++ b/tests/src/classes/crm/company/companyTest.php @@ -12,6 +12,7 @@ use Bitrix24\CRM\Company; use Bitrix24\Contracts\iBitrix24; + /** * @package Bitrix24 */ @@ -27,11 +28,11 @@ public function testUpdateCallsClientWithIdAndFields() //silly mocking in PHPUnit 4.8 $methods = array(); - $ref = new \ReflectionClass(iBitrix24::class); + $ref = new \ReflectionClass('Bitrix24\\Contracts\\iBitrix24'); foreach ($ref->getMethods() as $method) { $methods[] = $method->getName(); } - $client = $this->getMockBuilder(iBitrix24::class) + $client = $this->getMockBuilder('Bitrix24\\Contracts\\iBitrix24') ->setMethods($methods) ->getMock(); $client->expects($this->once()) From 5777d2ff58986d5e5df214a612227cebc2737e24 Mon Sep 17 00:00:00 2001 From: dnech Date: Thu, 14 Mar 2019 13:49:15 +0600 Subject: [PATCH 140/647] =?UTF-8?q?=D0=92=D0=BE=D0=B7=D0=B2=D1=80=D0=B0?= =?UTF-8?q?=D1=82=20=D0=BA=D0=BE=D1=80=D1=80=D0=B5=D0=BA=D1=82=D0=BD=D0=BE?= =?UTF-8?q?=D0=B3=D0=BE=20=D1=81=D0=BF=D0=B8=D1=81=D0=BA=D0=B0=20scope?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Если не передать текущие scope, то в возврате будет только один scope: app, что не соответствует списку наших текущих scope. Если мы в запросе отдадим наш список scope, то и в ответе его же получим. --- src/bitrix24.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bitrix24.php b/src/bitrix24.php index 842fa6f4..277c7cb0 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -274,6 +274,7 @@ public function getNewAccessToken() '&grant_type=refresh_token' . '&client_secret=' . $applicationSecret . '&refresh_token=' . $refreshToken . + '&scope=' . implode(',', $applicationScope) . '&redirect_uri=' . urlencode($redirectUri); $requestResult = $this->executeRequest($url); // handling bitrix24 api-level errors From f850836e82e2610943186abe0e5f036a48bbc146 Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Tue, 19 Mar 2019 23:59:52 +0300 Subject: [PATCH 141/647] task#132 --- src/bitrix24.php | 83 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 56 insertions(+), 27 deletions(-) diff --git a/src/bitrix24.php b/src/bitrix24.php index 277c7cb0..80abc7e8 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -30,7 +30,8 @@ /** * Class Bitrix24 - * @author Mesilov Maxim + * + * @author Mesilov Maxim * @copyright 2013 - 2016 Mesilov Maxim */ class Bitrix24 implements iBitrix24 @@ -146,13 +147,13 @@ class Bitrix24 implements iBitrix24 * @var bool ssl verify for checking CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST */ protected $sslVerify = true; - - + + /** * Create a object to work with Bitrix24 REST API service * - * @param bool $isSaveRawResponse - if true raw response from bitrix24 will be available from method getRawResponse, this is debug mode - * @param null|LoggerInterface $obLogger - instance of \Monolog\Logger + * @param bool $isSaveRawResponse - if true raw response from bitrix24 will be available from method getRawResponse, this is debug mode + * @param null|LoggerInterface $obLogger - instance of \Monolog\Logger * * @throws Bitrix24Exception * @@ -279,6 +280,7 @@ public function getNewAccessToken() $requestResult = $this->executeRequest($url); // handling bitrix24 api-level errors $this->handleBitrix24APILevelErrors($requestResult, 'refresh access token'); + return $requestResult; } @@ -307,6 +309,7 @@ public function setApplicationId($applicationId) throw new Bitrix24Exception('application id is empty'); } $this->applicationId = $applicationId; + return true; } @@ -335,6 +338,7 @@ public function setApplicationSecret($applicationSecret) throw new Bitrix24Exception('application secret is empty'); } $this->applicationSecret = $applicationSecret; + return true; } @@ -363,6 +367,7 @@ public function setRefreshToken($refreshToken) throw new Bitrix24Exception('refresh token is empty'); } $this->refreshToken = $refreshToken; + return true; } @@ -389,6 +394,7 @@ public function setApplicationScope(array $applicationScope) { if (is_array($applicationScope) && count($applicationScope) > 0) { $this->applicationScope = $applicationScope; + return true; } else { throw new Bitrix24Exception('application scope not set'); @@ -420,6 +426,7 @@ public function setRedirectUri($redirectUri) throw new Bitrix24Exception('redirect URI is empty'); } $this->redirectUri = $redirectUri; + return true; }// end of SetApplicationId @@ -448,30 +455,31 @@ public function setDomain($domain) throw new Bitrix24Exception('domain is empty'); } $this->domain = $domain; + return true; } /** * disable of checking CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST */ - public function setDisabledSslVerify () + public function setDisabledSslVerify() { $this->sslVerify = false; } - + /** * enable of checking CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST */ - public function setEnabledSslVerify () + public function setEnabledSslVerify() { $this->sslVerify = true; } - + /** * Execute a request API to Bitrix24 using cURL * * @param string $url - * @param array $additionalParameters + * @param array $additionalParameters * * @throws Bitrix24Exception * @throws Bitrix24PortalDeletedException @@ -490,7 +498,7 @@ protected function executeRequest($url, array $additionalParameters = array()) CURLE_READ_ERROR, CURLE_OPERATION_TIMEOUTED, CURLE_HTTP_POST_ERROR, - CURLE_SSL_CONNECT_ERROR + CURLE_SSL_CONNECT_ERROR, ); $curlOptions = array( @@ -503,11 +511,10 @@ protected function executeRequest($url, array $additionalParameters = array()) CURLOPT_USERAGENT => strtolower(__CLASS__ . '-PHP-SDK/v' . self::VERSION), CURLOPT_POST => true, CURLOPT_POSTFIELDS => http_build_query($additionalParameters), - CURLOPT_URL => $url + CURLOPT_URL => $url, ); - - if (!$this->sslVerify) - { + + if (!$this->sslVerify) { $curlOptions[CURLOPT_SSL_VERIFYPEER] = 0; $curlOptions[CURLOPT_SSL_VERIFYHOST] = 0; } @@ -583,6 +590,7 @@ protected function executeRequest($url, array $additionalParameters = array()) $this->log->error($errorMsg, $this->getErrorContext()); throw new Bitrix24Exception($errorMsg); } + return $jsonResult; } @@ -607,7 +615,7 @@ protected function getErrorContext() // network 'RAW_REQUEST' => $this->getRawRequest(), 'CURL_REQUEST_INFO' => $this->getRequestInfo(), - 'RAW_RESPONSE' => $this->getRawResponse() + 'RAW_RESPONSE' => $this->getRawResponse(), ); } @@ -638,6 +646,7 @@ public function setMemberId($memberId) throw new Bitrix24Exception('memberId is null'); } $this->memberId = $memberId; + return true; } @@ -666,6 +675,7 @@ public function setAccessToken($accessToken) throw new Bitrix24Exception('access token is empty'); } $this->accessToken = $accessToken; + return true; } @@ -713,7 +723,9 @@ public function getRetriesToConnectTimeout() /** * set retries to connect timeout in microseconds + * * @param int $microseconds + * * @return bool * @throws Bitrix24Exception */ @@ -724,14 +736,15 @@ public function setRetriesToConnectTimeout($microseconds = 1000000) throw new Bitrix24Exception('retries to connect count must be an integer'); } $this->retriesToConnectTimeout = $microseconds; + return true; } /** * Handling bitrix24 api-level errors * - * @param $arRequestResult - * @param $methodName + * @param $arRequestResult + * @param $methodName * @param array $additionalParameters * * @return null @@ -757,29 +770,37 @@ protected function handleBitrix24APILevelErrors( (array_key_exists('error_description', $arRequestResult) ? $arRequestResult['error_description'] : ''), $methodName, $this->getDomain()); - $this->log->error($errorMsg, $this->getErrorContext()); // throw specific API-level exceptions switch (strtoupper(trim($arRequestResult['error']))) { case 'WRONG_CLIENT': case 'ERROR_OAUTH': + $this->log->error($errorMsg, $this->getErrorContext()); throw new Bitrix24WrongClientException($errorMsg); case 'ERROR_METHOD_NOT_FOUND': + $this->log->error($errorMsg, $this->getErrorContext()); throw new Bitrix24MethodNotFoundException($errorMsg); case 'INVALID_TOKEN': case 'INVALID_GRANT': + $this->log->error($errorMsg, $this->getErrorContext()); throw new Bitrix24TokenIsInvalidException($errorMsg); case 'EXPIRED_TOKEN': + $this->log->notice($errorMsg, $this->getErrorContext()); throw new Bitrix24TokenIsExpiredException($errorMsg); case 'PAYMENT_REQUIRED': + $this->log->error($errorMsg, $this->getErrorContext()); throw new Bitrix24PaymentRequiredException($errorMsg); case 'NO_AUTH_FOUND': + $this->log->error($errorMsg, $this->getErrorContext()); throw new Bitrix24PortalRenamedException($errorMsg); case 'INSUFFICIENT_SCOPE': + $this->log->error($errorMsg, $this->getErrorContext()); throw new Bitrix24InsufficientScope($errorMsg); default: + $this->log->error($errorMsg, $this->getErrorContext()); throw new Bitrix24ApiException($errorMsg); } } + return null; } @@ -830,6 +851,7 @@ public function getFirstAccessToken($code) $requestResult = $this->executeRequest($url); // handling bitrix24 api-level errors $this->handleBitrix24APILevelErrors($requestResult, 'get first access token'); + return $requestResult; } @@ -873,6 +895,7 @@ public function isAccessTokenExpire() $this->handleBitrix24APILevelErrors($requestResult, 'app.info'); } } + return $isTokenExpire; }// end of isTokenExpire @@ -880,7 +903,7 @@ public function isAccessTokenExpire() * Get list of all methods available for current application * * @param array | null $applicationScope - * @param bool $isFull + * @param bool $isFull * * @return array * @@ -913,6 +936,7 @@ public function getAvailableMethods(array $applicationScope = array(), $isFull = $scope = '&scope=' . implode(',', array_map('urlencode', array_unique($applicationScope))); } $url = 'https://' . $domain . '/rest/methods.json?auth=' . $accessToken . $showAll . $scope; + return $this->executeRequest($url); } @@ -945,6 +969,7 @@ public function getScope($isFull = false) $showAll = '&full=true'; } $url = 'https://' . $domain . '/rest/scope.json?auth=' . $accessToken . $showAll; + return $this->executeRequest($url); } @@ -960,6 +985,7 @@ public function getRetriesToConnectCount() /** * set CURL request count retries + * * @param $retriesCnt * * @return boolean @@ -973,14 +999,15 @@ public function setRetriesToConnectCount($retriesCnt = 1) throw new Bitrix24Exception('retries to connect count must be an integer'); } $this->retriesToConnectCount = (int)$retriesCnt; + return true; } /** * Add call to batch. If [[$callback]] parameter is set, it will receive call result as first parameter. * - * @param string $method - * @param array $parameters + * @param string $method + * @param array $parameters * @param callable|null $callback * * @return string Unique call ID. @@ -993,6 +1020,7 @@ public function addBatchCall($method, array $parameters = array(), callable $cal 'parameters' => $parameters, 'callback' => $callback, ); + return $id; } @@ -1009,7 +1037,7 @@ public function hasBatchCalls() /** * Process batch calls. * - * @param int $halt Halt batch on error + * @param int $halt Halt batch on error * @param int $delay Delay between batch calls (in msec) * * @throws Bitrix24Exception @@ -1025,7 +1053,7 @@ public function processBatchCalls($halt = 0, $delay = self::BATCH_DELAY) $batchQueryCounter++; $slice = array_splice($this->_batch, 0, self::MAX_BATCH_CALLS); $this->log->info('bitrix24PhpSdk.processBatchCalls.callItem', array( - 'batch_query_number' => $batchQueryCounter + 'batch_query_number' => $batchQueryCounter, )); $commands = array(); @@ -1065,7 +1093,7 @@ public function processBatchCalls($halt = 0, $delay = self::BATCH_DELAY) * Execute Bitrix24 REST API method * * @param string $methodName - * @param array $additionalParameters + * @param array $additionalParameters * * @return mixed * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException @@ -1104,7 +1132,7 @@ public function call($methodName, array $additionalParameters = array()) * Execute Bitrix24 REST API method * * @param string $methodName - * @param array $additionalParameters + * @param array $additionalParameters * * @throws Bitrix24Exception * @throws Bitrix24ApiException @@ -1146,7 +1174,7 @@ protected function _call($methodName, array $additionalParameters = array()) $this->log->info('call bitrix24 method', array( 'BITRIX24_DOMAIN' => $this->domain, 'METHOD_NAME' => $methodName, - 'METHOD_PARAMETERS' => $additionalParameters + 'METHOD_PARAMETERS' => $additionalParameters, )); $requestResult = $this->executeRequest($url, $additionalParameters); // check errors and throw exception if errors exists @@ -1192,6 +1220,7 @@ protected function _call($methodName, array $additionalParameters = array()) throw new Bitrix24SecurityException('security signature in api-response not found'); } } + return $requestResult; } } From 6de93a66c1befc3fc38620a242393cec11738ce2 Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 20 Mar 2019 00:33:18 +0300 Subject: [PATCH 142/647] task#132 - update changelog --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 754b90cc..365b92fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,16 @@ # bitrix24-php-sdk change log +## 0.6.1 (20.03.2019) +* add `offset` parameter to entity `CRM\Status\Status` in method `getList` +* add `offset` parameter to entity `User\User` in method `getList` +* add method `messageAdd` to entity `Bitrix24\Bitrix24` +* add method `setEnabledSslVerify` to entity `Classes\Im\Im` +* add entity `Bitrix24\Bizproc\Provider` +* add entity `Bitrix24\CRM\Lead\ProductRows` class to work with products +* fix error in method `crm.company.update` +* fix error in method `Bitrix24::getNewAccessToken` +* fix error in method `Bizproc\Robot::add` +* fix log level in method `Bitrix24::handleBitrix24APILevelErrors` + ## 0.6.0 (18.02.2018) * add support for `FaceTracker` entity * add presets for request timing information From 0f134c471e55a91c75c14e017c55dd7b70dcf848 Mon Sep 17 00:00:00 2001 From: camaxtly Date: Sun, 9 Jun 2019 22:44:39 +0300 Subject: [PATCH 143/647] =?UTF-8?q?=D0=A4=D0=B8=D0=BA=D1=81=D0=B8=D1=80?= =?UTF-8?q?=D1=83=D0=B5=D0=BC=20=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/bitrix24.php | 52 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/src/bitrix24.php b/src/bitrix24.php index 80abc7e8..27c995af 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -235,6 +235,7 @@ public function getMethodParameters() /** * Get new access token * + * @link https://dev.1c-bitrix.ru/learning/course/index.php?COURSE_ID=99&LESSON_ID=10263&LESSON_PATH=8771.5380.5379.10263 * @return array * * @throws Bitrix24Exception @@ -269,15 +270,23 @@ public function getNewAccessToken() throw new Bitrix24Exception('application redirect URI not found, you must call setRedirectUri method before'); } -// $url = 'https://'.self::OAUTH_SERVER.'/oauth/token/'. - $url = 'https://' . $this->getDomain() . '/oauth/token/' . - '?client_id=' . urlencode($applicationId) . - '&grant_type=refresh_token' . - '&client_secret=' . $applicationSecret . - '&refresh_token=' . $refreshToken . - '&scope=' . implode(',', $applicationScope) . - '&redirect_uri=' . urlencode($redirectUri); +// $url = 'https://'.self::OAUTH_SERVER.'/oauth/token/' + $url = 'https://' . $this->getDomain() . '/oauth/token/' + . '?grant_type=refresh_token' + . '&client_id=' . urlencode($applicationId) + . '&client_secret=' . $applicationSecret + . '&refresh_token=' . $refreshToken + . '&scope=' . implode(',', $applicationScope) + . '&redirect_uri=' . urlencode($redirectUri) + ; + + var_dump($url); + + $requestResult = $this->executeRequest($url); + + var_dump($requestResult); + // handling bitrix24 api-level errors $this->handleBitrix24APILevelErrors($requestResult, 'refresh access token'); @@ -807,6 +816,7 @@ protected function handleBitrix24APILevelErrors( /** * Authorize and get first access token * + * @link https://dev.1c-bitrix.ru/learning/course/index.php?COURSE_ID=99&LESSON_ID=2486&LESSON_PATH=8771.5380.5379.2486 * @param $code * * @return array @@ -840,13 +850,14 @@ public function getFirstAccessToken($code) throw new Bitrix24Exception('application redirect URI not found, you must call setRedirectUri method before'); } -// $url = 'https://'.self::OAUTH_SERVER.'/oauth/token/'. - $url = 'https://' . $this->getDomain() . '/oauth/token/' . - '?client_id=' . urlencode($applicationId) . - '&grant_type=authorization_code' . - '&client_secret=' . $applicationSecret . - '&redirect_uri=' . urlencode($redirectUri) . - '&code=' . urlencode($code); +// $url = 'https://'.self::OAUTH_SERVER.'/oauth/token/' + $url = 'https://' . $this->getDomain() . '/oauth/token/' + . '?grant_type=authorization_code' + . '&client_id=' . urlencode($applicationId) + . '&client_secret=' . $applicationSecret + . '&code=' . urlencode($code) + . '&redirect_uri=' . urlencode($redirectUri) + ; $requestResult = $this->executeRequest($url); // handling bitrix24 api-level errors @@ -1170,6 +1181,9 @@ protected function _call($methodName, array $additionalParameters = array()) if (array_key_exists('state', $additionalParameters)) { $isSecureCall = true; } + + echo '
params '; print_r($additionalParameters); echo '
'; + // execute request $this->log->info('call bitrix24 method', array( 'BITRIX24_DOMAIN' => $this->domain, @@ -1199,11 +1213,19 @@ protected function _call($methodName, array $additionalParameters = array()) $signature = base64_decode(substr($requestResult['signature'], $delimiterPosition + 1)); // compare signatures $hash = hash_hmac('sha256', $dataToDecode, $key, true); + + echo '
result '; print_r($requestResult); echo '
'; + echo '
hash '; print_r($hash); echo '
'; + echo '
signature '; print_r($signature); echo '
'; + if ($hash !== $signature) { throw new Bitrix24SecurityException('security signatures not same, bad request'); } // decode $arClearData = json_decode(base64_decode($dataToDecode), true); + + echo '
arClearData '; print_r($arClearData); echo '
'; + // handling json_decode errors $jsonErrorCode = json_last_error(); if (null === $arClearData && (JSON_ERROR_NONE !== $jsonErrorCode)) { From 4f83f995da3a4296b17044a5feefe8b7e2db7f6c Mon Sep 17 00:00:00 2001 From: camaxtly Date: Thu, 13 Jun 2019 21:31:13 +0300 Subject: [PATCH 144/647] issue#136 use oauth server --- src/bitrix24.php | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/src/bitrix24.php b/src/bitrix24.php index 27c995af..9cb3cfaa 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -15,6 +15,7 @@ use Bitrix24\Exceptions\Bitrix24BadGatewayException; use Bitrix24\Exceptions\Bitrix24EmptyResponseException; use Bitrix24\Exceptions\Bitrix24Exception; +use Bitrix24\Exceptions\Bitrix24InsufficientScope; use Bitrix24\Exceptions\Bitrix24IoException; use Bitrix24\Exceptions\Bitrix24MethodNotFoundException; use Bitrix24\Exceptions\Bitrix24PaymentRequiredException; @@ -24,7 +25,6 @@ use Bitrix24\Exceptions\Bitrix24TokenIsExpiredException; use Bitrix24\Exceptions\Bitrix24TokenIsInvalidException; use Bitrix24\Exceptions\Bitrix24WrongClientException; -use Bitrix24\Exceptions\Bitrix24InsufficientScope; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; @@ -270,23 +270,15 @@ public function getNewAccessToken() throw new Bitrix24Exception('application redirect URI not found, you must call setRedirectUri method before'); } -// $url = 'https://'.self::OAUTH_SERVER.'/oauth/token/' - $url = 'https://' . $this->getDomain() . '/oauth/token/' + $url = 'https://' . self::OAUTH_SERVER . '/oauth/token/' . '?grant_type=refresh_token' . '&client_id=' . urlencode($applicationId) . '&client_secret=' . $applicationSecret . '&refresh_token=' . $refreshToken - . '&scope=' . implode(',', $applicationScope) - . '&redirect_uri=' . urlencode($redirectUri) ; - var_dump($url); - - $requestResult = $this->executeRequest($url); - var_dump($requestResult); - // handling bitrix24 api-level errors $this->handleBitrix24APILevelErrors($requestResult, 'refresh access token'); @@ -850,13 +842,11 @@ public function getFirstAccessToken($code) throw new Bitrix24Exception('application redirect URI not found, you must call setRedirectUri method before'); } -// $url = 'https://'.self::OAUTH_SERVER.'/oauth/token/' - $url = 'https://' . $this->getDomain() . '/oauth/token/' + $url = 'https://' . self::OAUTH_SERVER . '/oauth/token/' . '?grant_type=authorization_code' . '&client_id=' . urlencode($applicationId) . '&client_secret=' . $applicationSecret . '&code=' . urlencode($code) - . '&redirect_uri=' . urlencode($redirectUri) ; $requestResult = $this->executeRequest($url); @@ -895,9 +885,9 @@ public function isAccessTokenExpire() } elseif (null === $accessToken) { throw new Bitrix24Exception('application id not found, you must call setAccessToken method before'); } -// $url = 'https://'.self::OAUTH_SERVER.'/rest/app.info?auth='.$accessToken; - $url = 'https://' . $domain . '/rest/app.info?auth=' . $accessToken; + $url = 'https://' . self::OAUTH_SERVER . '/rest/app.info?auth=' . $accessToken; $requestResult = $this->executeRequest($url); + if (isset($requestResult['error'])) { if (in_array($requestResult['error'], array('expired_token', 'invalid_token', 'WRONG_TOKEN'), false)) { $isTokenExpire = true; @@ -1182,8 +1172,6 @@ protected function _call($methodName, array $additionalParameters = array()) $isSecureCall = true; } - echo '
params '; print_r($additionalParameters); echo '
'; - // execute request $this->log->info('call bitrix24 method', array( 'BITRIX24_DOMAIN' => $this->domain, @@ -1214,18 +1202,12 @@ protected function _call($methodName, array $additionalParameters = array()) // compare signatures $hash = hash_hmac('sha256', $dataToDecode, $key, true); - echo '
result '; print_r($requestResult); echo '
'; - echo '
hash '; print_r($hash); echo '
'; - echo '
signature '; print_r($signature); echo '
'; - if ($hash !== $signature) { throw new Bitrix24SecurityException('security signatures not same, bad request'); } // decode $arClearData = json_decode(base64_decode($dataToDecode), true); - echo '
arClearData '; print_r($arClearData); echo '
'; - // handling json_decode errors $jsonErrorCode = json_last_error(); if (null === $arClearData && (JSON_ERROR_NONE !== $jsonErrorCode)) { From 35d7dcc3a5cfd17c01e301b7bb6a1d1b50a219c0 Mon Sep 17 00:00:00 2001 From: Andrey Bolonin Date: Sun, 14 Jul 2019 15:31:32 +0300 Subject: [PATCH 145/647] add php 7.4snapshot --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 5b0d1d16..cc4dbc81 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ php: - 7.1 - 7.2 - 7.3 + - 7.4snapshot - hhvm matrix: From 5db3c5b9eefdc9367b5baae22ac53943211fbe5f Mon Sep 17 00:00:00 2001 From: camaxtly Date: Sun, 1 Sep 2019 20:41:39 +0300 Subject: [PATCH 146/647] added DealCategory --- src/classes/crm/deal/category.php | 261 ++++++++++++++++++++++++++++++ 1 file changed, 261 insertions(+) create mode 100644 src/classes/crm/deal/category.php diff --git a/src/classes/crm/deal/category.php b/src/classes/crm/deal/category.php new file mode 100644 index 00000000..54045ac0 --- /dev/null +++ b/src/classes/crm/deal/category.php @@ -0,0 +1,261 @@ +client->call( + 'crm.dealcategory.add', + array( + 'fields' => $fields, + 'params' => $params + ) + ); + return $fullResult; + } + + /** + * delete deal by id + * + * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_dealcategory_delete.php + * @var $id integer deal identifier + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + */ + public function delete($id) + { + $fullResult = $this->client->call( + 'crm.dealcategory.delete', + array('id' => $id) + ); + return $fullResult; + } + + /** + * get list of deal fields with description + * + * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_dealcategory_fields.php + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + */ + public function fields() + { + $fullResult = $this->client->call( + 'crm.dealcategory.fields' + ); + return $fullResult; + } + + /** + * get deal by id + * + * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_dealcategory_get.php + * @var $dealId integer deal identifier + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + */ + public function get($dealId) + { + $fullResult = $this->client->call( + 'crm.dealcategory.get', + array('id' => $dealId) + ); + return $fullResult; + } + + /** + * get default category + * + * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_dealcategory_default_get.php + * @var $dealId integer deal identifier + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + */ + public function getDefault() + { + $fullResult = $this->client->call( + 'crm.dealcategory.default.get' + ); + return $fullResult; + } + + /** + * update default category fields + * + * @param $fields + * @param array $params Set of parameters. REGISTER_SONET_EVENT - performs registration of a change event in + * a deal in the Activity Stream. The deals's Responsible person will also receive + * notification. + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_dealcategory_default_set.php + */ + public function setDefault($fields, $params = array()) + { + $fullResult = $this->client->call( + 'crm.dealcategory.default.set', + array( + 'fields' => $fields, + 'params' => $params + ) + ); + return $fullResult; + } + + /** + * Get list of deal items. + * + * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_dealcategory_list.php + * + * @param array $order - order of deal items + * @param array $filter - filter array + * @param array $select - array of collumns to select + * @param integer $start - entity number to start from (usually returned in 'next' field of previous + * 'crm.dealcategory.list' API call) + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + */ + public function getList($order = array(), $filter = array(), $select = array(), $start = 0) + { + $fullResult = $this->client->call( + 'crm.dealcategory.list', + array( + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $start + ) + ); + return $fullResult; + } + + /** + * update deal by id + * + * @param integer $dealId integer deal identifier + * @param array $dealFields array deal fields to update + * @param array $params Set of parameters. REGISTER_SONET_EVENT - performs registration of a change event in + * a deal in the Activity Stream. The deals's Responsible person will also receive + * notification. + * + * @return array + * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException + * @throws \Bitrix24\Exceptions\Bitrix24Exception + * @throws \Bitrix24\Exceptions\Bitrix24IoException + * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException + * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException + * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException + * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException + * @throws \Bitrix24\Exceptions\Bitrix24SecurityException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException + * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException + * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException + * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_dealcategory_update.php + */ + public function update($dealId, $dealFields, $params = array()) + { + $fullResult = $this->client->call( + 'crm.dealcategory.update', + array( + 'id' => $dealId, + 'fields' => $dealFields, + 'params' => $params + ) + ); + return $fullResult; + } +} From 39670916f6568d87605c03156065065f530366ed Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Thu, 12 Sep 2019 00:05:13 +0300 Subject: [PATCH 147/647] task#148 --- .travis.yml | 4 ---- CHANGELOG.md | 4 ++++ src/bitrix24.php | 42 +++++++++++++++++------------------------- 3 files changed, 21 insertions(+), 29 deletions(-) diff --git a/.travis.yml b/.travis.yml index cc4dbc81..f115c2c6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,6 @@ language: php php: - - 5.3.3 - - 5.4 - - 5.5 - - 5.6 - 7.0 - 7.1 - 7.2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 365b92fb..b230d782 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,8 @@ # bitrix24-php-sdk change log +## 0.6.2 (12.09.2019) +* remove in method, `processBatchCalls` remove call `handleBitrix24APILevelErrors` +* remove php 5.x branch in travis config + ## 0.6.1 (20.03.2019) * add `offset` parameter to entity `CRM\Status\Status` in method `getList` * add `offset` parameter to entity `User\User` in method `getList` diff --git a/src/bitrix24.php b/src/bitrix24.php index 9cb3cfaa..82d44eb8 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -155,9 +155,9 @@ class Bitrix24 implements iBitrix24 * @param bool $isSaveRawResponse - if true raw response from bitrix24 will be available from method getRawResponse, this is debug mode * @param null|LoggerInterface $obLogger - instance of \Monolog\Logger * + * @return Bitrix24 * @throws Bitrix24Exception * - * @return Bitrix24 */ public function __construct($isSaveRawResponse = false, LoggerInterface $obLogger = null) { @@ -274,8 +274,7 @@ public function getNewAccessToken() . '?grant_type=refresh_token' . '&client_id=' . urlencode($applicationId) . '&client_secret=' . $applicationSecret - . '&refresh_token=' . $refreshToken - ; + . '&refresh_token=' . $refreshToken; $requestResult = $this->executeRequest($url); @@ -300,9 +299,9 @@ public function getApplicationId() * * @param string $applicationId * + * @return true; * @throws Bitrix24Exception * - * @return true; */ public function setApplicationId($applicationId) { @@ -329,9 +328,9 @@ public function getApplicationSecret() * * @param string $applicationSecret * + * @return true; * @throws Bitrix24Exception * - * @return true; */ public function setApplicationSecret($applicationSecret) { @@ -358,9 +357,9 @@ public function getRefreshToken() * * @param $refreshToken * + * @return true; * @throws Bitrix24Exception * - * @return true; */ public function setRefreshToken($refreshToken) { @@ -417,9 +416,9 @@ public function getRedirectUri() * * @param string $redirectUri * + * @return true; * @throws Bitrix24Exception * - * @return true; */ public function setRedirectUri($redirectUri) { @@ -446,9 +445,9 @@ public function getDomain() * * @param $domain * + * @return true; * @throws Bitrix24Exception * - * @return true; */ public function setDomain($domain) { @@ -482,12 +481,12 @@ public function setEnabledSslVerify() * @param string $url * @param array $additionalParameters * - * @throws Bitrix24Exception + * @return array * @throws Bitrix24PortalDeletedException * @throws Bitrix24IoException * @throws Bitrix24EmptyResponseException * - * @return array + * @throws Bitrix24Exception * @throws \Bitrix24\Exceptions\Bitrix24BadGatewayException */ protected function executeRequest($url, array $additionalParameters = array()) @@ -635,9 +634,9 @@ public function getMemberId() * * @param string $memberId * + * @return true * @throws Bitrix24Exception * - * @return true */ public function setMemberId($memberId) { @@ -666,9 +665,9 @@ public function getAccessToken() * * @param string $accessToken * + * @return true * @throws Bitrix24Exception * - * @return true */ public function setAccessToken($accessToken) { @@ -809,6 +808,7 @@ protected function handleBitrix24APILevelErrors( * Authorize and get first access token * * @link https://dev.1c-bitrix.ru/learning/course/index.php?COURSE_ID=99&LESSON_ID=2486&LESSON_PATH=8771.5380.5379.2486 + * * @param $code * * @return array @@ -846,8 +846,7 @@ public function getFirstAccessToken($code) . '?grant_type=authorization_code' . '&client_id=' . urlencode($applicationId) . '&client_secret=' . $applicationSecret - . '&code=' . urlencode($code) - ; + . '&code=' . urlencode($code); $requestResult = $this->executeRequest($url); // handling bitrix24 api-level errors @@ -860,6 +859,7 @@ public function getFirstAccessToken($code) * Check is access token expire, call list of all available api-methods from B24 portal with current access token * if we have an error code expired_token then return true else return false * + * @return boolean * @throws Bitrix24Exception * @throws Bitrix24ApiException * @throws Bitrix24PortalDeletedException @@ -872,7 +872,6 @@ public function getFirstAccessToken($code) * @throws Bitrix24PaymentRequiredException * @throws Bitrix24PortalRenamedException * - * @return boolean */ public function isAccessTokenExpire() { @@ -946,14 +945,14 @@ public function getAvailableMethods(array $applicationScope = array(), $isFull = * * @param bool $isFull * - * @throws Bitrix24Exception + * @return array * @throws Bitrix24Exception * @throws Bitrix24PortalDeletedException * @throws Bitrix24PortalRenamedException * @throws Bitrix24IoException * @throws Bitrix24EmptyResponseException * - * @return array + * @throws Bitrix24Exception */ public function getScope($isFull = false) { @@ -1069,13 +1068,6 @@ public function processBatchCalls($halt = 0, $delay = self::BATCH_DELAY) continue; } - if (isset($results['result_error'][$idx])) { - $this->handleBitrix24APILevelErrors(array( - 'error' => $results['result_error'][$idx]['error'], - 'error_description' => $results['result_error'][$idx]['error_description'], - ), $call['method'], $call['parameters']); - } - call_user_func($call['callback'], array( 'result' => isset($results['result'][$idx]) ? $results['result'][$idx] : null, 'error' => isset($results['result_error'][$idx]) ? $results['result_error'][$idx] : null, @@ -1135,6 +1127,7 @@ public function call($methodName, array $additionalParameters = array()) * @param string $methodName * @param array $additionalParameters * + * @return array * @throws Bitrix24Exception * @throws Bitrix24ApiException * @throws Bitrix24TokenIsInvalidException @@ -1148,7 +1141,6 @@ public function call($methodName, array $additionalParameters = array()) * @throws Bitrix24EmptyResponseException * @throws Bitrix24PortalRenamedException * - * @return array */ protected function _call($methodName, array $additionalParameters = array()) { From 275be1297ac38d6b16d5d5616d6e1bb8cb633f1b Mon Sep 17 00:00:00 2001 From: Ievgenii Gardysh Date: Wed, 1 Apr 2020 22:55:51 +0300 Subject: [PATCH 148/647] changed two misspelling in comments --- src/bitrix24.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitrix24.php b/src/bitrix24.php index 82d44eb8..5838a467 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -83,12 +83,12 @@ class Bitrix24 implements iBitrix24 protected $rawRequest; /** - * @var array, contain all api-method parameters, vill be available after call method + * @var array, contain all api-method parameters, will be available after call method */ protected $methodParameters; /** - * @var array request info data structure акщь curl_getinfo function + * @var array request info data structure from curl_getinfo function */ protected $requestInfo; From a85df3ace3f68ce74ad5f2eefe949892c8b3c3ca Mon Sep 17 00:00:00 2001 From: Ievgenii Gardysh Date: Wed, 1 Apr 2020 23:35:52 +0300 Subject: [PATCH 149/647] Added support of API calls using webhook (without access_token) instead of application (requiring authorization) --- src/bitrix24.php | 117 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 115 insertions(+), 2 deletions(-) diff --git a/src/bitrix24.php b/src/bitrix24.php index 5838a467..8cc3d040 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -148,6 +148,15 @@ class Bitrix24 implements iBitrix24 */ protected $sslVerify = true; + /** + * @var bool if true - webhook will be used in API calls (without access_token) + */ + protected $webhook_usage; + + /** + * @var string webhook secret identifier + */ + protected $webhook_secret; /** * Create a object to work with Bitrix24 REST API service @@ -1105,7 +1114,8 @@ public function processBatchCalls($halt = 0, $delay = self::BATCH_DELAY) public function call($methodName, array $additionalParameters = array()) { try { - $result = $this->_call($methodName, $additionalParameters); + $result = $this->getWebhookUsage() ? $this->_call_webhook($methodName, $additionalParameters) + : $this->_call($methodName, $additionalParameters); } catch (Bitrix24TokenIsExpiredException $e) { if (!is_callable($this->_onExpiredToken)) { throw $e; @@ -1115,7 +1125,9 @@ public function call($methodName, array $additionalParameters = array()) if (!$retry) { throw $e; } - $result = $this->_call($methodName, $additionalParameters); + + $result = $this->getWebhookUsage() ? $this->_call_webhook($methodName, $additionalParameters) + : $this->_call($methodName, $additionalParameters); } return $result; @@ -1219,4 +1231,105 @@ protected function _call($methodName, array $additionalParameters = array()) return $requestResult; } + + /** + * Set whether we using webhook or application in API calls + * If true - use webhook in API call + * + * @param bool $webhook_usage_boolean + * @return bool + */ + public function setWebhookUsage($webhook_usage_boolean) + { + $this->webhook_usage = $webhook_usage_boolean; + + return true; + } + + /** + * Return whether we using webhook or application in API calls + * + * @return bool + */ + public function getWebhookUsage() + { + return $this->webhook_usage; + } + + /** + * Set webhook secret to use in API calls + * + * @param string $webhook_secret + * @return bool + */ + public function setWebhookSecret($webhook_secret) + { + $this->webhook_secret = $webhook_secret; + + return true; + } + + /** + * Return string with webhook secret + * + * @return string + */ + public function getWebhookSecret() + { + return $this->webhook_secret; + } + + /** + * Execute Bitrix24 REST API method using webhook + * + * @param string $methodName + * @param array $additionalParameters + * + * @return array + * @throws Bitrix24Exception + * @throws Bitrix24ApiException + * @throws Bitrix24TokenIsInvalidException + * @throws Bitrix24TokenIsExpiredException + * @throws Bitrix24WrongClientException + * @throws Bitrix24MethodNotFoundException + * @throws Bitrix24PaymentRequiredException + * @throws Bitrix24SecurityException + * @throws Bitrix24PortalDeletedException + * @throws Bitrix24IoException + * @throws Bitrix24EmptyResponseException + * @throws Bitrix24PortalRenamedException + */ + protected function _call_webhook($methodName, array $additionalParameters = array()) + { + if (null === $this->getDomain()) { + throw new Bitrix24Exception('domain not found, you must call setDomain method before'); + } + + if ('' === $methodName) { + throw new Bitrix24Exception('method name not found, you must set method name'); + } + + if (null === $this->getWebhookSecret()) { + throw new Bitrix24Exception('no webhook secret provided, you must call setWebhookSecret method before'); + } + + $url = 'https://' . $this->domain . '/rest/' . $this->getWebhookSecret() . '/' . $methodName; + + // save method parameters for debug + $this->methodParameters = $additionalParameters; + + // execute request + $this->log->info('call bitrix24 method', array( + 'BITRIX24_WEBHOOK_URL' => $url, + 'BITRIX24_DOMAIN' => $this->domain, + 'METHOD_NAME' => $methodName, + 'METHOD_PARAMETERS' => $additionalParameters, + )); + $requestResult = $this->executeRequest($url, $additionalParameters); + + // check errors and throw exception if errors exists + $this->handleBitrix24APILevelErrors($requestResult, $methodName, $additionalParameters); + + return $requestResult; + } } From 44f223a7382a20515cc1dfc74efbb1a554dbf4c1 Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Sat, 11 Jul 2020 01:09:18 +0300 Subject: [PATCH 150/647] issue#161 add return prop for crm-robots --- CHANGELOG.md | 3 +++ src/classes/bizproc/Robot.php | 49 +++++++++++++++++++---------------- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b230d782..877af283 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,7 @@ # bitrix24-php-sdk change log +## 0.7.0 (11.07.2020) +* add arguments in method `Bitrix24\Bizproc\Robot::add` for return results support + ## 0.6.2 (12.09.2019) * remove in method, `processBatchCalls` remove call `handleBitrix24APILevelErrors` * remove php 5.x branch in travis config diff --git a/src/classes/bizproc/Robot.php b/src/classes/bizproc/Robot.php index 12220583..cdba2417 100644 --- a/src/classes/bizproc/Robot.php +++ b/src/classes/bizproc/Robot.php @@ -12,18 +12,16 @@ class Robot extends Bitrix24Entity { /** - * add crm-robot - * - * @param string $code - * @param string $handler - * @param int $userId - * @param array $arName - * @param array $arProps + * @param $code + * @param $handler + * @param $userId + * @param $arName + * @param $arProps + * @param $arReturnProps + * @param $isUseSubscription + * @param $isUsePlacement * * @return mixed - * - * @see https://dev.1c-bitrix.ru/rest_help/bizproc/bizproc_robot/robotadd.php - * * @throws \Bitrix24\Exceptions\Bitrix24ApiException * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException * @throws \Bitrix24\Exceptions\Bitrix24Exception @@ -37,16 +35,21 @@ class Robot extends Bitrix24Entity * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException */ - public function add($code, $handler, $userId, $arName, $arProps) + public function add($code, $handler, $userId, $arName, $arProps, $arReturnProps, $isUseSubscription, $isUsePlacement) { - $arResult = $this->client->call('bizproc.robot.add', + $arResult = $this->client->call( + 'bizproc.robot.add', array( - 'CODE' => $code, - 'HANDLER' => $handler, - 'AUTH_USER_ID' => $userId, - 'NAME' => $arName, - 'PROPERTIES' => $arProps, - )); + 'CODE' => $code, + 'HANDLER' => $handler, + 'AUTH_USER_ID' => $userId, + 'NAME' => $arName, + 'PROPERTIES' => $arProps, + 'RETURN_PROPERTIES' => $arReturnProps, + 'USE_PLACEMENT' => $isUsePlacement === true ? 'Y' : 'N', + 'USE_SUBSCRIPTION' => $isUseSubscription === true ? 'Y' : 'N', + ) + ); return $arResult['result']; } @@ -56,8 +59,6 @@ public function add($code, $handler, $userId, $arName, $arProps) * * @param $code string * - * @see https://dev.1c-bitrix.ru/rest_help/bizproc/bizproc_robot/robotdelete.php - * * @return array * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException @@ -70,10 +71,13 @@ public function add($code, $handler, $userId, $arName, $arProps) * @throws \Bitrix24\Exceptions\Bitrix24Exception * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException * @throws \Bitrix24\Exceptions\Bitrix24ApiException + * @see https://dev.1c-bitrix.ru/rest_help/bizproc/bizproc_robot/robotdelete.php + * */ public function delete($code) { - $arResult = $this->client->call('bizproc.robot.delete', + $arResult = $this->client->call( + 'bizproc.robot.delete', array( 'code' => $code, ) @@ -103,7 +107,8 @@ public function delete($code) */ public function getList() { - $arResult = $this->client->call('bizproc.robot.list', + $arResult = $this->client->call( + 'bizproc.robot.list', array() ); From 81864e56e931484321b16d140f534d4199d661f9 Mon Sep 17 00:00:00 2001 From: bilovol Date: Tue, 21 Jul 2020 14:42:30 +0300 Subject: [PATCH 151/647] add support company user fields --- src/classes/crm/company/userfield.php | 97 +++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 src/classes/crm/company/userfield.php diff --git a/src/classes/crm/company/userfield.php b/src/classes/crm/company/userfield.php new file mode 100644 index 00000000..2b9eb435 --- /dev/null +++ b/src/classes/crm/company/userfield.php @@ -0,0 +1,97 @@ +client->call( + 'crm.company.userfield.list', + array( + 'order' => $order, + 'filter'=> $filter + ) + ); + return $fullResult; + } + + /** + * Get item userfield + * @link https://dev.1c-bitrix.ru/rest_help/crm/company/crm_company_userfield_get.php + * @param integer $userfieldId - company userfield id + * @return array + */ + public function get($userfieldId) + { + $fullResult = $this->client->call( + 'crm.company.userfield.get', + array('id' => $userfieldId) + ); + return $fullResult; + } + + /** + * Delete userfield + * @link https://dev.1c-bitrix.ru/rest_help/crm/company/crm_company_userfield_delete.php + * @param integer $userfieldId - company userfield id + * @return array + */ + public function delete($userfieldId) + { + $fullResult = $this->client->call( + 'crm.company.userfield.delete', + array('id' => $userfieldId) + ); + return $fullResult; + } + + /** + * Add a new userfield to company + * @param array $fields array of fields + * @link https://dev.1c-bitrix.ru/rest_help/crm/company/crm_company_userfield_add.php + * @return array + */ + public function add($fields = array()) + { + $fullResult = $this->client->call( + 'crm.company.userfield.add', + array('fields' => $fields) + ); + return $fullResult; + } + + + /** + * Updates userfield + * + * @param $id + * @param array $fields + * + * @link https://dev.1c-bitrix.ru/rest_help/crm/company/crm_company_userfield_update.php + * @return array + */ + public function update($id, $fields = array()) + { + $fullResult = $this->client->call( + 'crm.company.userfield.update', + array( + 'id' => $id, + 'fields' => $fields + ) + ); + + return $fullResult; + } +} From ac4ae3827e617952d5e88bccba91b4dbe46de13c Mon Sep 17 00:00:00 2001 From: Dmitry Date: Sat, 5 Sep 2020 12:49:21 +0400 Subject: [PATCH 152/647] Fix product.property "update" endpoint value add => update --- src/classes/crm/product/property.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/classes/crm/product/property.php b/src/classes/crm/product/property.php index ea939457..e3af8d79 100644 --- a/src/classes/crm/product/property.php +++ b/src/classes/crm/product/property.php @@ -112,7 +112,7 @@ public function add(array $fields) public function update($productPropertyId, array $fields) { $fullResult = $this->client->call( - 'crm.product.property.add', + 'crm.product.property.update', array( 'id' => $productPropertyId, 'fields' => $fields, @@ -133,4 +133,4 @@ public function getTypes() { return $this->client->call('crm.product.property.types'); } -} \ No newline at end of file +} From 8d539b7a24e172bcdec23dc34bae3811b0f49621 Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Sun, 18 Oct 2020 08:23:54 +0300 Subject: [PATCH 153/647] 1.x branch --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bb2bbc92..118ad265 100644 --- a/README.md +++ b/README.md @@ -9,9 +9,14 @@ A powerfull PHP library for the Bitrix24 REST API ## Promo code for new Bitrix24 accounts - `b24io5gb` — add 5GB on your Bitrix24 - `b24iousers` — add 12 users on your Bitrix24 - [Register new Bitrix24 account](https://www.bitrix24.ru/create.php?p=255670) +Bitrix24-PHP-SDK has a two branches +- 1.x with 5.x php support, bugfix and minor updates only +- 2.x only with 7.3+ php support, active work + +Current master is 1.x branch + ## Requirements - php: >=5.3.2 - ext-json: * From 784152f6ecacc5e19ed100c03c419dbc97100c74 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 18 Oct 2020 20:36:11 +0300 Subject: [PATCH 154/647] v2 dev 1 --- CHANGELOG.md | 4 + README.md | 67 +- composer.json | 69 +- examples/core/composer.json | 8 + examples/core/core-examp.php | 26 + src/Core/ApiClient.php | 113 ++ src/Core/Credentials/Credentials.php | 67 + src/Core/Credentials/OAuthToken.php | 55 + src/Core/Credentials/Scope.php | 28 + src/Core/Credentials/WebhookUrl.php | 33 + src/Services/Main.php | 1 + src/bitrix24.php | 1222 ----------------- src/classes/access.php | 28 - src/classes/app/app.php | 22 - src/classes/bitrix24application.php | 39 - src/classes/bitrix24entity.php | 24 - src/classes/bizproc/Activity.php | 125 -- src/classes/bizproc/Provider.php | 113 -- src/classes/bizproc/Robot.php | 117 -- src/classes/crm/activity/activity.php | 111 -- src/classes/crm/activity/communication.php | 23 - src/classes/crm/additional/duplicate.php | 31 - src/classes/crm/company/company.php | 119 -- src/classes/crm/contact/contact.php | 119 -- src/classes/crm/contact/userfield.php | 97 -- src/classes/crm/deal/category.php | 261 ---- src/classes/crm/deal/deal.php | 117 -- src/classes/crm/deal/productrows.php | 46 - src/classes/crm/deal/userfield.php | 112 -- src/classes/crm/enum/enum.php | 109 -- src/classes/crm/invoice/invoice.php | 232 ---- src/classes/crm/invoice/paysystem.php | 75 - src/classes/crm/invoice/persontype.php | 75 - src/classes/crm/invoice/status.php | 76 - src/classes/crm/invoice/userfield.php | 172 --- src/classes/crm/lead/lead.php | 113 -- src/classes/crm/lead/productrows.php | 45 - src/classes/crm/lead/userfield.php | 108 -- .../crm/livefeedmessage/livefeedmessage.php | 35 - src/classes/crm/product/product.php | 123 -- src/classes/crm/product/property.php | 136 -- src/classes/crm/productrow/productrow.php | 49 - .../crm/productsection/productsection.php | 197 --- src/classes/crm/quote/quote.php | 106 -- src/classes/crm/requisite/address.php | 131 -- src/classes/crm/requisite/bank.php | 148 -- src/classes/crm/requisite/link.php | 143 -- src/classes/crm/requisite/preset.php | 207 --- src/classes/crm/requisite/presetfield.php | 225 --- src/classes/crm/requisite/requisite.php | 150 -- src/classes/crm/requisite/userfield.php | 156 --- src/classes/crm/status/status.php | 245 ---- src/classes/departments/department.php | 98 -- src/classes/entity/entity.php | 310 ----- src/classes/event/event.php | 101 -- src/classes/event/util.php | 29 - src/classes/facetracker/client.php | 58 - src/classes/facetracker/user.php | 79 -- src/classes/im/attach/attach.php | 129 -- src/classes/im/attach/iattach.php | 49 - src/classes/im/attach/iattachitem.php | 30 - src/classes/im/attach/item/delimiter.php | 60 - src/classes/im/attach/item/file.php | 67 - src/classes/im/attach/item/grid.php | 114 -- src/classes/im/attach/item/image.php | 60 - src/classes/im/attach/item/link.php | 75 - src/classes/im/attach/item/message.php | 52 - src/classes/im/attach/item/user.php | 68 - src/classes/im/chat.php | 289 ---- src/classes/im/im.php | 91 -- src/classes/im/notify.php | 175 --- src/classes/log/blogpost.php | 46 - src/classes/placement/Placement.php | 74 - src/classes/sonet/sonetgroup.php | 179 --- src/classes/task/checklistitem.php | 169 --- src/classes/task/commentitem.php | 115 -- src/classes/task/elapseditem.php | 141 -- src/classes/task/item.php | 237 ---- src/classes/task/items.php | 34 - src/classes/task/planner.php | 20 - src/classes/user/user.php | 83 -- src/classes/userfieldtype/UserfieldType.php | 126 -- src/contracts/ibitrix24.php | 364 ----- src/exceptions/bitrix24apiexception.php | 18 - .../bitrix24badgatewayexception.php | 18 - .../bitrix24emptyresponseexception.php | 18 - src/exceptions/bitrix24exception.php | 33 - src/exceptions/bitrix24insufficientscope.php | 18 - src/exceptions/bitrix24ioexception.php | 18 - .../bitrix24methodnotfoundexception.php | 18 - .../bitrix24paymentrequiredexception.php | 18 - .../bitrix24portaldeletedexception.php | 18 - .../bitrix24portalrenamedexception.php | 18 - src/exceptions/bitrix24securityexception.php | 18 - .../bitrix24tokenisexpiredexception.php | 18 - .../bitrix24tokenisinvalidexception.php | 18 - .../bitrix24wrongclientexception.php | 18 - src/presets/app/app.php | 85 -- src/presets/crm/additional/entitytypes.php | 30 - src/presets/crm/additional/fields.php | 22 - src/presets/crm/company/fields.php | 110 -- src/presets/crm/contact/fields.php | 183 --- src/presets/crm/deal/fields.php | 147 -- src/presets/crm/invoice/fields.php | 52 - src/presets/crm/lead/fields.php | 204 --- src/presets/crm/lead/userfield/fields.php | 31 - src/presets/crm/product/ProductRowFields.php | 98 -- src/presets/crm/product/fields.php | 72 - src/presets/departments/fields.php | 15 - src/presets/event/event.php | 190 --- src/presets/event/fields.php | 29 - src/presets/im/fields.php | 17 - src/presets/im/ichatcolor.php | 82 -- src/presets/lang.php | 41 - src/presets/main.php | 33 - src/presets/placement/Fields.php | 27 - src/presets/placement/Placement.php | 76 - src/presets/scope.php | 103 -- src/presets/task/item/fields.php | 216 --- src/presets/timing.php | 44 - src/presets/uri.php | 13 - src/presets/userfields.php | 15 - src/presets/users/fields.php | 45 - src/stub/bitrix24.php | 478 ------- tests/src/Bitrix24Test.php | 125 -- tests/src/classes/crm/company/companyTest.php | 51 - tests/src/classes/im/attach/attachTest.php | 74 - .../classes/im/attach/item/delimiterTest.php | 30 - tests/src/classes/im/attach/item/fileTest.php | 30 - tests/src/classes/im/attach/item/gridTest.php | 30 - .../src/classes/im/attach/item/imageTest.php | 30 - tests/src/classes/im/attach/item/linkTest.php | 30 - .../classes/im/attach/item/messageTest.php | 30 - tests/src/classes/im/attach/item/userTest.php | 30 - tests/src/classes/im/chatTest.php | 268 ---- 135 files changed, 402 insertions(+), 12826 deletions(-) create mode 100644 examples/core/composer.json create mode 100644 examples/core/core-examp.php create mode 100644 src/Core/ApiClient.php create mode 100644 src/Core/Credentials/Credentials.php create mode 100644 src/Core/Credentials/OAuthToken.php create mode 100644 src/Core/Credentials/Scope.php create mode 100644 src/Core/Credentials/WebhookUrl.php create mode 100644 src/Services/Main.php delete mode 100644 src/bitrix24.php delete mode 100644 src/classes/access.php delete mode 100644 src/classes/app/app.php delete mode 100644 src/classes/bitrix24application.php delete mode 100644 src/classes/bitrix24entity.php delete mode 100644 src/classes/bizproc/Activity.php delete mode 100644 src/classes/bizproc/Provider.php delete mode 100644 src/classes/bizproc/Robot.php delete mode 100644 src/classes/crm/activity/activity.php delete mode 100644 src/classes/crm/activity/communication.php delete mode 100644 src/classes/crm/additional/duplicate.php delete mode 100644 src/classes/crm/company/company.php delete mode 100644 src/classes/crm/contact/contact.php delete mode 100644 src/classes/crm/contact/userfield.php delete mode 100644 src/classes/crm/deal/category.php delete mode 100644 src/classes/crm/deal/deal.php delete mode 100644 src/classes/crm/deal/productrows.php delete mode 100644 src/classes/crm/deal/userfield.php delete mode 100644 src/classes/crm/enum/enum.php delete mode 100644 src/classes/crm/invoice/invoice.php delete mode 100644 src/classes/crm/invoice/paysystem.php delete mode 100644 src/classes/crm/invoice/persontype.php delete mode 100644 src/classes/crm/invoice/status.php delete mode 100644 src/classes/crm/invoice/userfield.php delete mode 100644 src/classes/crm/lead/lead.php delete mode 100644 src/classes/crm/lead/productrows.php delete mode 100644 src/classes/crm/lead/userfield.php delete mode 100644 src/classes/crm/livefeedmessage/livefeedmessage.php delete mode 100644 src/classes/crm/product/product.php delete mode 100644 src/classes/crm/product/property.php delete mode 100644 src/classes/crm/productrow/productrow.php delete mode 100644 src/classes/crm/productsection/productsection.php delete mode 100644 src/classes/crm/quote/quote.php delete mode 100644 src/classes/crm/requisite/address.php delete mode 100644 src/classes/crm/requisite/bank.php delete mode 100644 src/classes/crm/requisite/link.php delete mode 100644 src/classes/crm/requisite/preset.php delete mode 100644 src/classes/crm/requisite/presetfield.php delete mode 100644 src/classes/crm/requisite/requisite.php delete mode 100644 src/classes/crm/requisite/userfield.php delete mode 100644 src/classes/crm/status/status.php delete mode 100644 src/classes/departments/department.php delete mode 100644 src/classes/entity/entity.php delete mode 100644 src/classes/event/event.php delete mode 100644 src/classes/event/util.php delete mode 100644 src/classes/facetracker/client.php delete mode 100644 src/classes/facetracker/user.php delete mode 100644 src/classes/im/attach/attach.php delete mode 100644 src/classes/im/attach/iattach.php delete mode 100644 src/classes/im/attach/iattachitem.php delete mode 100644 src/classes/im/attach/item/delimiter.php delete mode 100644 src/classes/im/attach/item/file.php delete mode 100644 src/classes/im/attach/item/grid.php delete mode 100644 src/classes/im/attach/item/image.php delete mode 100644 src/classes/im/attach/item/link.php delete mode 100644 src/classes/im/attach/item/message.php delete mode 100644 src/classes/im/attach/item/user.php delete mode 100644 src/classes/im/chat.php delete mode 100644 src/classes/im/im.php delete mode 100644 src/classes/im/notify.php delete mode 100644 src/classes/log/blogpost.php delete mode 100644 src/classes/placement/Placement.php delete mode 100644 src/classes/sonet/sonetgroup.php delete mode 100644 src/classes/task/checklistitem.php delete mode 100644 src/classes/task/commentitem.php delete mode 100644 src/classes/task/elapseditem.php delete mode 100644 src/classes/task/item.php delete mode 100644 src/classes/task/items.php delete mode 100644 src/classes/task/planner.php delete mode 100644 src/classes/user/user.php delete mode 100644 src/classes/userfieldtype/UserfieldType.php delete mode 100644 src/contracts/ibitrix24.php delete mode 100644 src/exceptions/bitrix24apiexception.php delete mode 100644 src/exceptions/bitrix24badgatewayexception.php delete mode 100644 src/exceptions/bitrix24emptyresponseexception.php delete mode 100644 src/exceptions/bitrix24exception.php delete mode 100644 src/exceptions/bitrix24insufficientscope.php delete mode 100644 src/exceptions/bitrix24ioexception.php delete mode 100644 src/exceptions/bitrix24methodnotfoundexception.php delete mode 100644 src/exceptions/bitrix24paymentrequiredexception.php delete mode 100644 src/exceptions/bitrix24portaldeletedexception.php delete mode 100644 src/exceptions/bitrix24portalrenamedexception.php delete mode 100644 src/exceptions/bitrix24securityexception.php delete mode 100644 src/exceptions/bitrix24tokenisexpiredexception.php delete mode 100644 src/exceptions/bitrix24tokenisinvalidexception.php delete mode 100644 src/exceptions/bitrix24wrongclientexception.php delete mode 100644 src/presets/app/app.php delete mode 100644 src/presets/crm/additional/entitytypes.php delete mode 100644 src/presets/crm/additional/fields.php delete mode 100644 src/presets/crm/company/fields.php delete mode 100644 src/presets/crm/contact/fields.php delete mode 100644 src/presets/crm/deal/fields.php delete mode 100644 src/presets/crm/invoice/fields.php delete mode 100644 src/presets/crm/lead/fields.php delete mode 100644 src/presets/crm/lead/userfield/fields.php delete mode 100644 src/presets/crm/product/ProductRowFields.php delete mode 100644 src/presets/crm/product/fields.php delete mode 100644 src/presets/departments/fields.php delete mode 100644 src/presets/event/event.php delete mode 100644 src/presets/event/fields.php delete mode 100644 src/presets/im/fields.php delete mode 100644 src/presets/im/ichatcolor.php delete mode 100644 src/presets/lang.php delete mode 100644 src/presets/main.php delete mode 100644 src/presets/placement/Fields.php delete mode 100644 src/presets/placement/Placement.php delete mode 100644 src/presets/scope.php delete mode 100644 src/presets/task/item/fields.php delete mode 100644 src/presets/timing.php delete mode 100644 src/presets/uri.php delete mode 100644 src/presets/userfields.php delete mode 100644 src/presets/users/fields.php delete mode 100644 src/stub/bitrix24.php delete mode 100644 tests/src/Bitrix24Test.php delete mode 100644 tests/src/classes/crm/company/companyTest.php delete mode 100644 tests/src/classes/im/attach/attachTest.php delete mode 100644 tests/src/classes/im/attach/item/delimiterTest.php delete mode 100644 tests/src/classes/im/attach/item/fileTest.php delete mode 100644 tests/src/classes/im/attach/item/gridTest.php delete mode 100644 tests/src/classes/im/attach/item/imageTest.php delete mode 100644 tests/src/classes/im/attach/item/linkTest.php delete mode 100644 tests/src/classes/im/attach/item/messageTest.php delete mode 100644 tests/src/classes/im/attach/item/userTest.php delete mode 100644 tests/src/classes/im/chatTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 877af283..95329f81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,8 @@ # bitrix24-php-sdk change log +## 2.0 DEV +* remove all old code + + ## 0.7.0 (11.07.2020) * add arguments in method `Bitrix24\Bizproc\Robot::add` for return results support diff --git a/README.md b/README.md index 118ad265..bd09c490 100644 --- a/README.md +++ b/README.md @@ -2,54 +2,47 @@ bitrix24-php-sdk [![Build Status](https://travis-ci.org/mesilov/bitrix24-php-sdk ================ [![License](https://poser.pugx.org/mesilov/bitrix24-php-sdk/license.svg)](https://packagist.org/packages/mesilov/bitrix24-php-sdk) [![Total Downloads](https://poser.pugx.org/mesilov/bitrix24-php-sdk/downloads.svg)](https://packagist.org/packages/mesilov/bitrix24-php-sdk) -A powerfull PHP library for the Bitrix24 REST API +A powerful PHP library for the Bitrix24 REST API [Bitrix24 API documentation - Russian](http://dev.1c-bitrix.ru/rest_help/)
[Bitrix24 API documentation - English](https://training.bitrix24.com/rest_help/) -## Promo code for new Bitrix24 accounts -- `b24io5gb` — add 5GB on your Bitrix24 -- `b24iousers` — add 12 users on your Bitrix24 [Register new Bitrix24 account](https://www.bitrix24.ru/create.php?p=255670) -Bitrix24-PHP-SDK has a two branches -- 1.x with 5.x php support, bugfix and minor updates only -- 2.x only with 7.3+ php support, active work +Bitrix24 auth features +- work with auth tokens +- work with incoming webhooks -Current master is 1.x branch +add low-level tools to devs: +- 2.1 callbacks +- 2.2 rate-limiter - wait for symfony/symfony#37471 +- 2.3 RetryHttpClient - symfony/symfony#38182 + +API - level features +- 3.1 batch queries +- 3.2 offline queues +- 3.3 add change domain URL support + +## Architecture +``` + /Core + ApiClient.php - default api-client, work on http abstraction layer, return - Symfony\Contracts\HttpClient\ResponseInterface + /Services + /CRM + /Deals + /Client + Deals.php + /Exceptions + /Tasks + … + Main.php - default bitrix24 rest api service provide basic funcions, work with data transfer objects +``` ## Requirements -- php: >=5.3.2 +- php: >=7.4 - ext-json: * -- ext-curl: * -- Monolog: optional +- ext-curl: * ## Example ## -``` php -pushHandler(new StreamHandler('path/to/your.log', Logger::DEBUG)); - - -// init lib -$obB24App = new \Bitrix24\Bitrix24(false, $log); -$obB24App->setApplicationScope($arParams['B24_APPLICATION_SCOPE']); -$obB24App->setApplicationId($arParams['B24_APPLICATION_ID']); -$obB24App->setApplicationSecret($arParams['B24_APPLICATION_SECRET']); - -// set user-specific settings -$obB24App->setDomain($arParams['DOMAIN']); -$obB24App->setMemberId($arParams['MEMBER_ID']); -$obB24App->setAccessToken($arParams['AUTH_ID']); -$obB24App->setRefreshToken($arParams['REFRESH_ID']); - -// get information about current user from bitrix24 -$obB24User = new \Bitrix24\User\User($obB24App); -$arCurrentB24User = $obB24User->current(); -``` ## Installation ## Add `"mesilov/bitrix24-php-sdk": "dev-master"` to `composer.json` of your application. Or clone repo to your project. diff --git a/composer.json b/composer.json index dcd28c60..3563cc45 100644 --- a/composer.json +++ b/composer.json @@ -1,35 +1,40 @@ { - "name": "mesilov/bitrix24-php-sdk", - "description": "A powerfull PHP library for the Bitrix24 REST API", - "keywords": ["Bitrix24", "PHP", "REST", "API"], - "type": "library", - "homepage": "https://github.com/mesilov/bitrix24-php-sdk", - "license": "MIT", - "authors": [ - { - "name": "Maxim Mesilov", - "homepage": "https://github.com/mesilov/" - } - ], - "require": { - "php": ">=5.3.2", - "ext-json": "*", - "ext-curl": "*", - "psr/log": "^1.0" - }, - "require-dev": { - "jakub-onderka/php-parallel-lint": "0.9", - "jakub-onderka/php-console-highlighter": "~0.3", - "phpunit/phpunit": "~4.8", - "phpunit/phpunit-mock-objects": "2.3.0" - }, - "autoload": { - "classmap": ["src/"] - }, - "scripts": { - "test": [ - "parallel-lint . --exclude vendor --no-colors", - "phpunit --colors=always --verbose" - ] + "name": "mesilov/bitrix24-php-sdk", + "description": "A powerful PHP library for the Bitrix24 REST API", + "keywords": [ + "Bitrix24", + "PHP", + "REST", + "API" + ], + "type": "library", + "homepage": "https://github.com/mesilov/bitrix24-php-sdk", + "license": "MIT", + "authors": [ + { + "name": "Maxim Mesilov", + "homepage": "https://github.com/mesilov/" } + ], + "require": { + "php": ">=7.3", + "ext-json": "*", + "ext-curl": "*", + "psr/log": "1.1.3", + "symfony/http-client": "5.1.*" + }, + "require-dev": { + "phpunit/phpunit": "9.3.*", + "roave/security-advisories": "dev-master" + }, + "autoload": { + "psr-4": { + "Bitrix24\\SDK\\": "src" + } + }, + "scripts": { + "test": [ + "phpunit --colors=always --verbose" + ] + } } \ No newline at end of file diff --git a/examples/core/composer.json b/examples/core/composer.json new file mode 100644 index 00000000..ceb68f23 --- /dev/null +++ b/examples/core/composer.json @@ -0,0 +1,8 @@ +{ + "require": { + "monolog/monolog": "2.*" + }, + "require-dev": { + "roave/security-advisories": "dev-master" + } +} \ No newline at end of file diff --git a/examples/core/core-examp.php b/examples/core/core-examp.php new file mode 100644 index 00000000..e4d01a0e --- /dev/null +++ b/examples/core/core-examp.php @@ -0,0 +1,26 @@ +pushHandler(new StreamHandler('b24-api-client-debug.log', Logger::DEBUG)); + +$client = HttpClient::create(); + +$credentials = new \Bitrix24\SDK\Core\Credentials\Credentials( + new \Bitrix24\SDK\Core\Credentials\WebhookUrl('b24 domain'), + null, + null +); + +$apiClient = new \Bitrix24\SDK\Core\ApiClient($credentials, $client, $log); + +$result = $apiClient->getResponse('crm.deal.get', ['id' => 5]); + +var_dump($result->getContent()); diff --git a/src/Core/ApiClient.php b/src/Core/ApiClient.php new file mode 100644 index 00000000..e8dbec1b --- /dev/null +++ b/src/Core/ApiClient.php @@ -0,0 +1,113 @@ +credentials = $credentials; + $this->client = $client; + $this->logger = $logger; + } + + /** + * @return Credentials\Credentials + */ + public function getCredentials(): Credentials\Credentials + { + return $this->credentials; + } + + /** + * @param Credentials\Credentials $credentials + */ + public function setCredentials(Credentials\Credentials $credentials): void + { + $this->credentials = $credentials; + } + + /** + * @return OAuthToken + */ + public function getNewToken(): OAuthToken + { + return new OAuthToken('1', '2', 3600); + } + + /** + * @param string $apiMethod + * @param array $parameters + * + * @return ResponseInterface + * @throws TransportExceptionInterface + */ + public function getResponse(string $apiMethod, array $parameters = []): ResponseInterface + { + $this->logger->debug( + sprintf('getResponse.start %s', $apiMethod), + [ + 'domainUrl' => $this->credentials->getDomainUrl(), + 'parameters' => $parameters, + ] + ); + + $method = 'POST'; + + if ($this->credentials->getWebhookUrl() !== null) { + $url = sprintf('%s/%s/', $this->credentials->getWebhookUrl()->getUrl(), $apiMethod); + } else { + // todo domain rename case + $url = sprintf('%s/%s', $this->credentials->getDomainUrl(), $apiMethod); + } + + + $requestOptions = [ + 'json' => $parameters, + ]; + + $response = $this->client->request($method, $url, $requestOptions); + + $this->logger->debug( + sprintf('getResponse.end %s', $apiMethod), + [ + 'responseInfo' => $response->getInfo(), + ] + ); + + return $response; + } +} \ No newline at end of file diff --git a/src/Core/Credentials/Credentials.php b/src/Core/Credentials/Credentials.php new file mode 100644 index 00000000..a00c9296 --- /dev/null +++ b/src/Core/Credentials/Credentials.php @@ -0,0 +1,67 @@ +webhookUrl = $webhookUrl; + $this->oauthToken = $oauthToken; + $this->domainUrl = $domainUrl; + if ($this->oauthToken === null && $this->webhookUrl === null) { + throw new \LogicException(sprintf('you must set on of auth type: webhook or oauth')); + } + if ($this->oauthToken !== null && $this->domainUrl === null) { + throw new \LogicException(sprintf('for oauth type you must set domain url')); + } + } + + /** + * @return string + */ + public function getDomainUrl(): string + { + if ($this->getWebhookUrl() !== null) { + $url = parse_url($this->getWebhookUrl()->getUrl())['host']; + } else { + $url = $this->getDomainUrl(); + } + + return $url; + } + + /** + * @return WebhookUrl|null + */ + public function getWebhookUrl(): ?WebhookUrl + { + return $this->webhookUrl; + } + + /** + * @return OAuthToken|null + */ + public function getOauthToken(): ?OAuthToken + { + return $this->oauthToken; + } +} \ No newline at end of file diff --git a/src/Core/Credentials/OAuthToken.php b/src/Core/Credentials/OAuthToken.php new file mode 100644 index 00000000..2a745a6d --- /dev/null +++ b/src/Core/Credentials/OAuthToken.php @@ -0,0 +1,55 @@ +authToken = $authToken; + $this->refreshToken = $refreshToken; + $this->expiresIn = $expiresIn; + } + + /** + * @return string + */ + public function getAuthToken(): string + { + return $this->authToken; + } + + /** + * @return string + */ + public function getRefreshToken(): string + { + return $this->refreshToken; + } + + /** + * @return int + */ + public function getExpiresIn(): int + { + return $this->expiresIn; + } +} \ No newline at end of file diff --git a/src/Core/Credentials/Scope.php b/src/Core/Credentials/Scope.php new file mode 100644 index 00000000..c5ec8e2e --- /dev/null +++ b/src/Core/Credentials/Scope.php @@ -0,0 +1,28 @@ +url = $webhookUrl; + } + + /** + * @return string + */ + public function getUrl(): string + { + return $this->url; + } +} \ No newline at end of file diff --git a/src/Services/Main.php b/src/Services/Main.php new file mode 100644 index 00000000..b3d9bbc7 --- /dev/null +++ b/src/Services/Main.php @@ -0,0 +1 @@ + - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24; - -use Bitrix24\Contracts\iBitrix24; -use Bitrix24\Exceptions\Bitrix24ApiException; -use Bitrix24\Exceptions\Bitrix24BadGatewayException; -use Bitrix24\Exceptions\Bitrix24EmptyResponseException; -use Bitrix24\Exceptions\Bitrix24Exception; -use Bitrix24\Exceptions\Bitrix24InsufficientScope; -use Bitrix24\Exceptions\Bitrix24IoException; -use Bitrix24\Exceptions\Bitrix24MethodNotFoundException; -use Bitrix24\Exceptions\Bitrix24PaymentRequiredException; -use Bitrix24\Exceptions\Bitrix24PortalDeletedException; -use Bitrix24\Exceptions\Bitrix24PortalRenamedException; -use Bitrix24\Exceptions\Bitrix24SecurityException; -use Bitrix24\Exceptions\Bitrix24TokenIsExpiredException; -use Bitrix24\Exceptions\Bitrix24TokenIsInvalidException; -use Bitrix24\Exceptions\Bitrix24WrongClientException; -use Psr\Log\LoggerInterface; -use Psr\Log\NullLogger; - -/** - * Class Bitrix24 - * - * @author Mesilov Maxim - * @copyright 2013 - 2016 Mesilov Maxim - */ -class Bitrix24 implements iBitrix24 -{ - /** - * @var string SDK version - */ - const VERSION = '1.0'; - - /** - * @var string OAuth server - */ - const OAUTH_SERVER = 'oauth.bitrix.info'; - - - /** - * @var string access token - */ - protected $accessToken; - - /** - * @var string refresh token - */ - protected $refreshToken; - - /** - * @var string domain - */ - protected $domain; - - /** - * @var array scope - */ - protected $applicationScope = array(); - - /** - * @var string application id - */ - protected $applicationId; - - /** - * @var string application secret - */ - protected $applicationSecret; - - /** - * @var array raw request, contain all cURL options array and API query - */ - protected $rawRequest; - - /** - * @var array, contain all api-method parameters, will be available after call method - */ - protected $methodParameters; - - /** - * @var array request info data structure from curl_getinfo function - */ - protected $requestInfo; - - /** - * @var bool if true raw response from bitrix24 will be available from method getRawResponse, this is debug mode - */ - protected $isSaveRawResponse = false; - - /** - * @var array raw response from bitrix24 - */ - protected $rawResponse; - - /** - * @var string redirect URI from application settings - */ - protected $redirectUri; - - /** - * @var string portal GUID - */ - protected $memberId; - - /** - * @var array custom options for cURL - */ - protected $customCurlOptions; - - /** - * @see https://github.com/Seldaek/monolog - * @var \Monolog\Logger PSR-3 compatible logger, use only from wrappers methods log* - */ - protected $log; - - /** - * @var integer CURL request count retries - */ - protected $retriesToConnectCount; - - /** - * @var integer retries to connect timeout in microseconds - */ - protected $retriesToConnectTimeout; - - /** - * @var array pending batch calls - */ - protected $_batch = array(); - - /** - * @var callable callback for expired tokens - */ - protected $_onExpiredToken; - - /** - * @var bool ssl verify for checking CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST - */ - protected $sslVerify = true; - - - /** - * Create a object to work with Bitrix24 REST API service - * - * @param bool $isSaveRawResponse - if true raw response from bitrix24 will be available from method getRawResponse, this is debug mode - * @param null|LoggerInterface $obLogger - instance of \Monolog\Logger - * - * @return Bitrix24 - * @throws Bitrix24Exception - * - */ - public function __construct($isSaveRawResponse = false, LoggerInterface $obLogger = null) - { - if (!extension_loaded('curl')) { - throw new Bitrix24Exception('cURL extension must be installed to use this library'); - } - if (!is_bool($isSaveRawResponse)) { - throw new Bitrix24Exception('isSaveRawResponse flag must be boolean'); - } - $this->isSaveRawResponse = $isSaveRawResponse; - if ($obLogger !== null) { - /** - * @var \Monolog\Logger - */ - $this->log = clone $obLogger; - } else { - // dev/null logger - /** - * @var \Monolog\Logger - */ - $this->log = new NullLogger(); - } - $this->setRetriesToConnectCount(1); - $this->setRetriesToConnectTimeout(1000000); - } - - /** - * Set function called on token expiration. Callback receives instance as first parameter. - * If callback returns true, API call will be retried. - * - * @param callable $callback - */ - public function setOnExpiredToken(callable $callback) - { - $this->_onExpiredToken = $callback; - } - - /** - * Get a random string to sign protected api-call. Use salt for argument "state" in secure api-call - * random string is a result of mt_rand function - * - * @return int - */ - public function getSecuritySignSalt() - { - return mt_rand(); - } - - /** - * Set custom cURL options, overriding default ones - * - * @link http://php.net/manual/en/function.curl-setopt.php - * - * @param array $options - array(CURLOPT_XXX => value1, CURLOPT_XXX2 => value2,...) - * - * @return bool - */ - public function setCustomCurlOptions($options) - { - $this->customCurlOptions = $options; - - return true; - } - - /** - * Return additional parameters of last api-call. Data available after you try to call method call - * - * @return array | null - */ - public function getMethodParameters() - { - return $this->methodParameters; - } - - /** - * Get new access token - * - * @link https://dev.1c-bitrix.ru/learning/course/index.php?COURSE_ID=99&LESSON_ID=10263&LESSON_PATH=8771.5380.5379.10263 - * @return array - * - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * @throws Bitrix24TokenIsInvalidException - * @throws Bitrix24TokenIsExpiredException - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24PaymentRequiredException - * @throws Bitrix24PortalRenamedException - */ - public function getNewAccessToken() - { - $applicationId = $this->getApplicationId(); - $applicationSecret = $this->getApplicationSecret(); - $refreshToken = $this->getRefreshToken(); - $applicationScope = $this->getApplicationScope(); - $redirectUri = $this->getRedirectUri(); - - if (null === $applicationId) { - throw new Bitrix24Exception('application id not found, you must call setApplicationId method before'); - } elseif (null === $applicationSecret) { - throw new Bitrix24Exception('application id not found, you must call setApplicationSecret method before'); - } elseif (null === $refreshToken) { - throw new Bitrix24Exception('application id not found, you must call setRefreshToken method before'); - } elseif (0 === count($applicationScope)) { - throw new Bitrix24Exception('application scope not found, you must call setApplicationScope method before'); - } elseif (null === $redirectUri) { - throw new Bitrix24Exception('application redirect URI not found, you must call setRedirectUri method before'); - } - - $url = 'https://' . self::OAUTH_SERVER . '/oauth/token/' - . '?grant_type=refresh_token' - . '&client_id=' . urlencode($applicationId) - . '&client_secret=' . $applicationSecret - . '&refresh_token=' . $refreshToken; - - $requestResult = $this->executeRequest($url); - - // handling bitrix24 api-level errors - $this->handleBitrix24APILevelErrors($requestResult, 'refresh access token'); - - return $requestResult; - } - - /** - * Get application id - * - * @return string - */ - public function getApplicationId() - { - return $this->applicationId; - } - - /** - * Set application id - * - * @param string $applicationId - * - * @return true; - * @throws Bitrix24Exception - * - */ - public function setApplicationId($applicationId) - { - if ('' === $applicationId) { - throw new Bitrix24Exception('application id is empty'); - } - $this->applicationId = $applicationId; - - return true; - } - - /** - * Get application secret - * - * @return string - */ - public function getApplicationSecret() - { - return $this->applicationSecret; - } - - /** - * Set application secret - * - * @param string $applicationSecret - * - * @return true; - * @throws Bitrix24Exception - * - */ - public function setApplicationSecret($applicationSecret) - { - if ('' === $applicationSecret) { - throw new Bitrix24Exception('application secret is empty'); - } - $this->applicationSecret = $applicationSecret; - - return true; - } - - /** - * Get refresh token - * - * @return string - */ - public function getRefreshToken() - { - return $this->refreshToken; - } - - /** - * Set refresh token - * - * @param $refreshToken - * - * @return true; - * @throws Bitrix24Exception - * - */ - public function setRefreshToken($refreshToken) - { - if ('' === $refreshToken) { - throw new Bitrix24Exception('refresh token is empty'); - } - $this->refreshToken = $refreshToken; - - return true; - } - - /** - * Get application scope - * - * @return string - */ - public function getApplicationScope() - { - return $this->applicationScope; - } - - /** - * Set application scope - * - * @param array $applicationScope - * - * @return boolean - * - * @throws Bitrix24Exception - */ - public function setApplicationScope(array $applicationScope) - { - if (is_array($applicationScope) && count($applicationScope) > 0) { - $this->applicationScope = $applicationScope; - - return true; - } else { - throw new Bitrix24Exception('application scope not set'); - } - } - - /** - * Get redirect URI - * - * @return string | null - */ - public function getRedirectUri() - { - return $this->redirectUri; - } - - /** - * Set redirect URI - * - * @param string $redirectUri - * - * @return true; - * @throws Bitrix24Exception - * - */ - public function setRedirectUri($redirectUri) - { - if ('' === $redirectUri) { - throw new Bitrix24Exception('redirect URI is empty'); - } - $this->redirectUri = $redirectUri; - - return true; - }// end of SetApplicationId - - /** - * Get domain - * - * @return string | null - */ - public function getDomain() - { - return $this->domain; - } - - /** - * Set domain - * - * @param $domain - * - * @return true; - * @throws Bitrix24Exception - * - */ - public function setDomain($domain) - { - if ('' === $domain) { - throw new Bitrix24Exception('domain is empty'); - } - $this->domain = $domain; - - return true; - } - - /** - * disable of checking CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST - */ - public function setDisabledSslVerify() - { - $this->sslVerify = false; - } - - /** - * enable of checking CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST - */ - public function setEnabledSslVerify() - { - $this->sslVerify = true; - } - - /** - * Execute a request API to Bitrix24 using cURL - * - * @param string $url - * @param array $additionalParameters - * - * @return array - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * - * @throws Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24BadGatewayException - */ - protected function executeRequest($url, array $additionalParameters = array()) - { - $retryableErrorCodes = array( - CURLE_COULDNT_RESOLVE_HOST, - CURLE_COULDNT_CONNECT, - CURLE_HTTP_NOT_FOUND, - CURLE_READ_ERROR, - CURLE_OPERATION_TIMEOUTED, - CURLE_HTTP_POST_ERROR, - CURLE_SSL_CONNECT_ERROR, - ); - - $curlOptions = array( - CURLOPT_FOLLOWLOCATION => true, - CURLOPT_RETURNTRANSFER => true, - CURLINFO_HEADER_OUT => true, - CURLOPT_VERBOSE => true, - CURLOPT_CONNECTTIMEOUT => 65, - CURLOPT_TIMEOUT => 70, - CURLOPT_USERAGENT => strtolower(__CLASS__ . '-PHP-SDK/v' . self::VERSION), - CURLOPT_POST => true, - CURLOPT_POSTFIELDS => http_build_query($additionalParameters), - CURLOPT_URL => $url, - ); - - if (!$this->sslVerify) { - $curlOptions[CURLOPT_SSL_VERIFYPEER] = 0; - $curlOptions[CURLOPT_SSL_VERIFYHOST] = 0; - } - - if (is_array($this->customCurlOptions)) { - foreach ($this->customCurlOptions as $customCurlOptionKey => $customCurlOptionValue) { - $curlOptions[$customCurlOptionKey] = $customCurlOptionValue; - } - } - - $this->rawRequest = $curlOptions; - $curl = curl_init(); - curl_setopt_array($curl, $curlOptions); - - $curlResult = false; - $retriesCnt = $this->retriesToConnectCount; - while ($retriesCnt--) { - $this->log->debug(sprintf('try [%s] to connect to host [%s]', $retriesCnt, $this->getDomain())); - $curlResult = curl_exec($curl); - // handling network I/O errors - if (false === $curlResult) { - $curlErrorNumber = curl_errno($curl); - $errorMsg = sprintf('in try[%s] cURL error (code %s): %s' . PHP_EOL, $retriesCnt, $curlErrorNumber, - curl_error($curl)); - if (false === in_array($curlErrorNumber, $retryableErrorCodes, true) || !$retriesCnt) { - $this->log->error($errorMsg, $this->getErrorContext()); - curl_close($curl); - throw new Bitrix24IoException($errorMsg); - } else { - $this->log->warning($errorMsg, $this->getErrorContext()); - } - usleep($this->getRetriesToConnectTimeout()); - continue; - } - $this->requestInfo = curl_getinfo($curl); - $this->rawResponse = $curlResult; - $this->log->debug('cURL request info', array($this->getRequestInfo())); - curl_close($curl); - break; - } - - // handling URI level resource errors - switch ($this->requestInfo['http_code']) { - case 403: - $errorMsg = sprintf('portal [%s] deleted, query aborted', $this->getDomain()); - $this->log->error($errorMsg, $this->getErrorContext()); - throw new Bitrix24PortalDeletedException($errorMsg); - break; - - case 502: - $errorMsg = sprintf('bad gateway to portal [%s]', $this->getDomain()); - $this->log->error($errorMsg, $this->getErrorContext()); - throw new Bitrix24BadGatewayException($errorMsg); - break; - } - - // handling server-side API errors: empty response from bitrix24 portal - if ($curlResult === '') { - $errorMsg = sprintf('empty response from portal [%s]', $this->getDomain()); - $this->log->error($errorMsg, $this->getErrorContext()); - throw new Bitrix24EmptyResponseException($errorMsg); - } - - // handling json_decode errors - $jsonResult = json_decode($curlResult, true); - unset($curlResult); - $jsonErrorCode = json_last_error(); - if (null === $jsonResult && (JSON_ERROR_NONE !== $jsonErrorCode)) { - /** - * @todo add function json_last_error_msg() - */ - $errorMsg = 'fatal error in function json_decode.' . PHP_EOL . 'Error code: ' . $jsonErrorCode . PHP_EOL; - $this->log->error($errorMsg, $this->getErrorContext()); - throw new Bitrix24Exception($errorMsg); - } - - return $jsonResult; - } - - /** - * get error context - * - * @return array - */ - protected function getErrorContext() - { - return array( - // portal specific settings - 'B24_DOMAIN' => $this->getDomain(), - 'B24_MEMBER_ID' => $this->getMemberId(), - 'B24_ACCESS_TOKEN' => $this->getAccessToken(), - 'B24_REFRESH_TOKEN' => $this->getRefreshToken(), - // application settings - 'APPLICATION_SCOPE' => $this->getApplicationScope(), - 'APPLICATION_ID' => $this->getApplicationId(), - 'APPLICATION_SECRET' => $this->getApplicationSecret(), - 'REDIRECT_URI' => $this->getRedirectUri(), - // network - 'RAW_REQUEST' => $this->getRawRequest(), - 'CURL_REQUEST_INFO' => $this->getRequestInfo(), - 'RAW_RESPONSE' => $this->getRawResponse(), - ); - } - - /** - * Get memeber ID - * - * @return string | null - */ - public function getMemberId() - { - return $this->memberId; - } - - /** - * Set member ID — portal GUID - * - * @param string $memberId - * - * @return true - * @throws Bitrix24Exception - * - */ - public function setMemberId($memberId) - { - if ('' === $memberId) { - throw new Bitrix24Exception('memberId is empty'); - } elseif (null === $memberId) { - throw new Bitrix24Exception('memberId is null'); - } - $this->memberId = $memberId; - - return true; - } - - /** - * Get access token - * - * @return string | null - */ - public function getAccessToken() - { - return $this->accessToken; - } - - /** - * Set access token - * - * @param string $accessToken - * - * @return true - * @throws Bitrix24Exception - * - */ - public function setAccessToken($accessToken) - { - if ('' === $accessToken) { - throw new Bitrix24Exception('access token is empty'); - } - $this->accessToken = $accessToken; - - return true; - } - - /** - * Return raw request, contain all cURL options array and API query. Data available after you try to call method call - * numbers of array keys is const of cURL module. Example: CURLOPT_RETURNTRANSFER = 19913 - * - * @return array | null - */ - public function getRawRequest() - { - return $this->rawRequest; - } - - /** - * Return result from function curl_getinfo. Data available after you try to call method call - * - * @return array | null - */ - public function getRequestInfo() - { - return $this->requestInfo; - } - - /** - * Get raw response from Bitrix24 before json_decode call, method available only in debug mode. - * To activate debug mode you must before set to true flag isSaveRawResponse in class construct - * - * @return string | null - */ - public function getRawResponse() - { - return $this->rawResponse; - } - - /** - * get retries to connect timeout in microseconds - * - * @return mixed - */ - public function getRetriesToConnectTimeout() - { - return $this->retriesToConnectTimeout; - } - - /** - * set retries to connect timeout in microseconds - * - * @param int $microseconds - * - * @return bool - * @throws Bitrix24Exception - */ - public function setRetriesToConnectTimeout($microseconds = 1000000) - { - $this->log->debug(sprintf('set retries to connect count %s', $microseconds)); - if (!is_numeric($microseconds)) { - throw new Bitrix24Exception('retries to connect count must be an integer'); - } - $this->retriesToConnectTimeout = $microseconds; - - return true; - } - - /** - * Handling bitrix24 api-level errors - * - * @param $arRequestResult - * @param $methodName - * @param array $additionalParameters - * - * @return null - * - * @throws Bitrix24ApiException - * @throws Bitrix24TokenIsInvalidException - * @throws Bitrix24TokenIsExpiredException - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24PaymentRequiredException - * @throws Bitrix24PortalRenamedException - * @throws Bitrix24InsufficientScope - */ - protected function handleBitrix24APILevelErrors( - $arRequestResult, - $methodName, - array $additionalParameters = array() - ) - { - if (array_key_exists('error', $arRequestResult)) { - $errorMsg = sprintf('%s - %s in call [%s] for domain [%s]', - $arRequestResult['error'], - (array_key_exists('error_description', $arRequestResult) ? $arRequestResult['error_description'] : ''), - $methodName, - $this->getDomain()); - // throw specific API-level exceptions - switch (strtoupper(trim($arRequestResult['error']))) { - case 'WRONG_CLIENT': - case 'ERROR_OAUTH': - $this->log->error($errorMsg, $this->getErrorContext()); - throw new Bitrix24WrongClientException($errorMsg); - case 'ERROR_METHOD_NOT_FOUND': - $this->log->error($errorMsg, $this->getErrorContext()); - throw new Bitrix24MethodNotFoundException($errorMsg); - case 'INVALID_TOKEN': - case 'INVALID_GRANT': - $this->log->error($errorMsg, $this->getErrorContext()); - throw new Bitrix24TokenIsInvalidException($errorMsg); - case 'EXPIRED_TOKEN': - $this->log->notice($errorMsg, $this->getErrorContext()); - throw new Bitrix24TokenIsExpiredException($errorMsg); - case 'PAYMENT_REQUIRED': - $this->log->error($errorMsg, $this->getErrorContext()); - throw new Bitrix24PaymentRequiredException($errorMsg); - case 'NO_AUTH_FOUND': - $this->log->error($errorMsg, $this->getErrorContext()); - throw new Bitrix24PortalRenamedException($errorMsg); - case 'INSUFFICIENT_SCOPE': - $this->log->error($errorMsg, $this->getErrorContext()); - throw new Bitrix24InsufficientScope($errorMsg); - default: - $this->log->error($errorMsg, $this->getErrorContext()); - throw new Bitrix24ApiException($errorMsg); - } - } - - return null; - } - - /** - * Authorize and get first access token - * - * @link https://dev.1c-bitrix.ru/learning/course/index.php?COURSE_ID=99&LESSON_ID=2486&LESSON_PATH=8771.5380.5379.2486 - * - * @param $code - * - * @return array - * - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * @throws Bitrix24TokenIsInvalidException - * @throws Bitrix24TokenIsExpiredException - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24PaymentRequiredException - * @throws Bitrix24PortalRenamedException - */ - public function getFirstAccessToken($code) - { - $applicationId = $this->getApplicationId(); - $applicationSecret = $this->getApplicationSecret(); - $applicationScope = $this->getApplicationScope(); - $redirectUri = $this->getRedirectUri(); - - if (null === $applicationId) { - throw new Bitrix24Exception('application id not found, you must call setApplicationId method before'); - } elseif (null === $applicationSecret) { - throw new Bitrix24Exception('application id not found, you must call setApplicationSecret method before'); - } elseif (0 === count($applicationScope)) { - throw new Bitrix24Exception('application scope not found, you must call setApplicationScope method before'); - } elseif (null === $redirectUri) { - throw new Bitrix24Exception('application redirect URI not found, you must call setRedirectUri method before'); - } - - $url = 'https://' . self::OAUTH_SERVER . '/oauth/token/' - . '?grant_type=authorization_code' - . '&client_id=' . urlencode($applicationId) - . '&client_secret=' . $applicationSecret - . '&code=' . urlencode($code); - - $requestResult = $this->executeRequest($url); - // handling bitrix24 api-level errors - $this->handleBitrix24APILevelErrors($requestResult, 'get first access token'); - - return $requestResult; - } - - /** - * Check is access token expire, call list of all available api-methods from B24 portal with current access token - * if we have an error code expired_token then return true else return false - * - * @return boolean - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * @throws Bitrix24TokenIsInvalidException - * @throws Bitrix24TokenIsExpiredException - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24PaymentRequiredException - * @throws Bitrix24PortalRenamedException - * - */ - public function isAccessTokenExpire() - { - $isTokenExpire = false; - $accessToken = $this->getAccessToken(); - $domain = $this->getDomain(); - - if (null === $domain) { - throw new Bitrix24Exception('domain not found, you must call setDomain method before'); - } elseif (null === $accessToken) { - throw new Bitrix24Exception('application id not found, you must call setAccessToken method before'); - } - $url = 'https://' . self::OAUTH_SERVER . '/rest/app.info?auth=' . $accessToken; - $requestResult = $this->executeRequest($url); - - if (isset($requestResult['error'])) { - if (in_array($requestResult['error'], array('expired_token', 'invalid_token', 'WRONG_TOKEN'), false)) { - $isTokenExpire = true; - } else { - // handle other errors - $this->handleBitrix24APILevelErrors($requestResult, 'app.info'); - } - } - - return $isTokenExpire; - }// end of isTokenExpire - - /** - * Get list of all methods available for current application - * - * @param array | null $applicationScope - * @param bool $isFull - * - * @return array - * - * @throws Bitrix24Exception - * @throws Bitrix24Exception - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24PortalRenamedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - */ - public function getAvailableMethods(array $applicationScope = array(), $isFull = false) - { - $accessToken = $this->getAccessToken(); - $domain = $this->getDomain(); - - if (null === $domain) { - throw new Bitrix24Exception('domain not found, you must call setDomain method before'); - } elseif (null === $accessToken) { - throw new Bitrix24Exception('application id not found, you must call setAccessToken method before'); - } - - $showAll = ''; - if (true === $isFull) { - $showAll = '&full=true'; - } - $scope = ''; - if (null === $applicationScope) { - $scope = '&scope'; - } elseif (count(array_unique($applicationScope)) > 0) { - $scope = '&scope=' . implode(',', array_map('urlencode', array_unique($applicationScope))); - } - $url = 'https://' . $domain . '/rest/methods.json?auth=' . $accessToken . $showAll . $scope; - - return $this->executeRequest($url); - } - - /** - * get list of scope for current application from bitrix24 api - * - * @param bool $isFull - * - * @return array - * @throws Bitrix24Exception - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24PortalRenamedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * - * @throws Bitrix24Exception - */ - public function getScope($isFull = false) - { - $accessToken = $this->getAccessToken(); - $domain = $this->getDomain(); - - if (null === $domain) { - throw new Bitrix24Exception('domain not found, you must call setDomain method before'); - } elseif (null === $accessToken) { - throw new Bitrix24Exception('application id not found, you must call setAccessToken method before'); - } - $showAll = ''; - if (true === $isFull) { - $showAll = '&full=true'; - } - $url = 'https://' . $domain . '/rest/scope.json?auth=' . $accessToken . $showAll; - - return $this->executeRequest($url); - } - - /** - * get CURL request count retries - * - * @return int - */ - public function getRetriesToConnectCount() - { - return $this->retriesToConnectCount; - } - - /** - * set CURL request count retries - * - * @param $retriesCnt - * - * @return boolean - * - * @throws Bitrix24Exception - */ - public function setRetriesToConnectCount($retriesCnt = 1) - { - $this->log->debug(sprintf('set retries to connect count %s', $retriesCnt)); - if (!is_int($retriesCnt)) { - throw new Bitrix24Exception('retries to connect count must be an integer'); - } - $this->retriesToConnectCount = (int)$retriesCnt; - - return true; - } - - /** - * Add call to batch. If [[$callback]] parameter is set, it will receive call result as first parameter. - * - * @param string $method - * @param array $parameters - * @param callable|null $callback - * - * @return string Unique call ID. - */ - public function addBatchCall($method, array $parameters = array(), callable $callback = null) - { - $id = uniqid(); - $this->_batch[$id] = array( - 'method' => $method, - 'parameters' => $parameters, - 'callback' => $callback, - ); - - return $id; - } - - /** - * Return true, if we have unprocessed batch calls. - * - * @return bool - */ - public function hasBatchCalls() - { - return (bool)count($this->_batch); - } - - /** - * Process batch calls. - * - * @param int $halt Halt batch on error - * @param int $delay Delay between batch calls (in msec) - * - * @throws Bitrix24Exception - * @throws Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - */ - public function processBatchCalls($halt = 0, $delay = self::BATCH_DELAY) - { - $this->log->info('Bitrix24PhpSdk.processBatchCalls.start', array('batch_query_delay' => $delay)); - $batchQueryCounter = 0; - while (count($this->_batch)) { - $batchQueryCounter++; - $slice = array_splice($this->_batch, 0, self::MAX_BATCH_CALLS); - $this->log->info('bitrix24PhpSdk.processBatchCalls.callItem', array( - 'batch_query_number' => $batchQueryCounter, - )); - - $commands = array(); - foreach ($slice as $idx => $call) { - $commands[$idx] = $call['method'] . '?' . http_build_query($call['parameters']); - } - - $batchResult = $this->call('batch', array('halt' => $halt, 'cmd' => $commands)); - $results = $batchResult['result']; - foreach ($slice as $idx => $call) { - if (!isset($call['callback']) || !is_callable($call['callback'])) { - continue; - } - - call_user_func($call['callback'], array( - 'result' => isset($results['result'][$idx]) ? $results['result'][$idx] : null, - 'error' => isset($results['result_error'][$idx]) ? $results['result_error'][$idx] : null, - 'total' => isset($results['result_total'][$idx]) ? $results['result_total'][$idx] : null, - 'next' => isset($results['result_next'][$idx]) ? $results['result_next'][$idx] : null, - )); - } - if (count($this->_batch) && $delay) { - usleep($delay); - } - } - $this->log->info('bitrix24PhpSdk.processBatchCalls.finish'); - } - - /** - * Execute Bitrix24 REST API method - * - * @param string $methodName - * @param array $additionalParameters - * - * @return mixed - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws Bitrix24TokenIsExpiredException - */ - public function call($methodName, array $additionalParameters = array()) - { - try { - $result = $this->_call($methodName, $additionalParameters); - } catch (Bitrix24TokenIsExpiredException $e) { - if (!is_callable($this->_onExpiredToken)) { - throw $e; - } - - $retry = call_user_func($this->_onExpiredToken, $this); - if (!$retry) { - throw $e; - } - $result = $this->_call($methodName, $additionalParameters); - } - - return $result; - } - - /** - * Execute Bitrix24 REST API method - * - * @param string $methodName - * @param array $additionalParameters - * - * @return array - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24TokenIsInvalidException - * @throws Bitrix24TokenIsExpiredException - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24PaymentRequiredException - * @throws Bitrix24SecurityException - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * @throws Bitrix24PortalRenamedException - * - */ - protected function _call($methodName, array $additionalParameters = array()) - { - if (null === $this->getDomain()) { - throw new Bitrix24Exception('domain not found, you must call setDomain method before'); - } - if (null === $this->getAccessToken()) { - throw new Bitrix24Exception('access token not found, you must call setAccessToken method before'); - } - if ('' === $methodName) { - throw new Bitrix24Exception('method name not found, you must set method name'); - } - - $url = 'https://' . $this->domain . '/rest/' . $methodName; - $additionalParameters['auth'] = $this->accessToken; - // save method parameters for debug - $this->methodParameters = $additionalParameters; - // is secure api-call? - $isSecureCall = false; - if (array_key_exists('state', $additionalParameters)) { - $isSecureCall = true; - } - - // execute request - $this->log->info('call bitrix24 method', array( - 'BITRIX24_DOMAIN' => $this->domain, - 'METHOD_NAME' => $methodName, - 'METHOD_PARAMETERS' => $additionalParameters, - )); - $requestResult = $this->executeRequest($url, $additionalParameters); - // check errors and throw exception if errors exists - $this->handleBitrix24APILevelErrors($requestResult, $methodName, $additionalParameters); - // handling security sign for secure api-call - if ($isSecureCall) { - if (array_key_exists('signature', $requestResult)) { - // check signature structure - if (strpos($requestResult['signature'], '.') === false) { - throw new Bitrix24SecurityException('security signature is corrupted'); - } - if (null === $this->getMemberId()) { - throw new Bitrix24Exception('member-id not found, you must call setMemberId method before'); - } - if (null === $this->getApplicationSecret()) { - throw new Bitrix24Exception('application secret not found, you must call setApplicationSecret method before'); - } - // prepare - $key = md5($this->getMemberId() . $this->getApplicationSecret()); - $delimiterPosition = strrpos($requestResult['signature'], '.'); - $dataToDecode = substr($requestResult['signature'], 0, $delimiterPosition); - $signature = base64_decode(substr($requestResult['signature'], $delimiterPosition + 1)); - // compare signatures - $hash = hash_hmac('sha256', $dataToDecode, $key, true); - - if ($hash !== $signature) { - throw new Bitrix24SecurityException('security signatures not same, bad request'); - } - // decode - $arClearData = json_decode(base64_decode($dataToDecode), true); - - // handling json_decode errors - $jsonErrorCode = json_last_error(); - if (null === $arClearData && (JSON_ERROR_NONE !== $jsonErrorCode)) { - /** - * @todo add function json_last_error_msg() - */ - $errorMsg = 'fatal error in function json_decode.' . PHP_EOL . 'Error code: ' . $jsonErrorCode . PHP_EOL; - throw new Bitrix24Exception($errorMsg); - } - // merge dirty and clear data - unset($arClearData['state']); - $requestResult ['result'] = array_merge($requestResult ['result'], $arClearData); - } else { - throw new Bitrix24SecurityException('security signature in api-response not found'); - } - } - - return $requestResult; - } -} diff --git a/src/classes/access.php b/src/classes/access.php deleted file mode 100644 index 7f2676b2..00000000 --- a/src/classes/access.php +++ /dev/null @@ -1,28 +0,0 @@ -client->call( - 'access.name', - array( - 'ACCESS' => $access - ) - ); - - return $result; - } -} - diff --git a/src/classes/app/app.php b/src/classes/app/app.php deleted file mode 100644 index 1d6fb866..00000000 --- a/src/classes/app/app.php +++ /dev/null @@ -1,22 +0,0 @@ -client->call('app.info', array('state' => $this->client->getSecuritySignSalt())); - return $result; - } -} \ No newline at end of file diff --git a/src/classes/bitrix24application.php b/src/classes/bitrix24application.php deleted file mode 100644 index 70311d89..00000000 --- a/src/classes/bitrix24application.php +++ /dev/null @@ -1,39 +0,0 @@ -client = $client; - } -} \ No newline at end of file diff --git a/src/classes/bizproc/Activity.php b/src/classes/bizproc/Activity.php deleted file mode 100644 index 074b7895..00000000 --- a/src/classes/bizproc/Activity.php +++ /dev/null @@ -1,125 +0,0 @@ -client->call('bizproc.activity.add', - array( - 'CODE' => $code, - 'HANDLER' => $handler, - 'AUTH_USER_ID' => $userId, - 'USE_SUBSCRIPTION' => $subscription, - 'NAME' => $arName, - 'DESCRIPTION' => $arDescription, - 'PROPERTIES' => $arProps, - 'RETURN_PROPERTIES' => $arReturnProps, - 'DOCUMENT_TYPE' => $arDocType, - 'FILTER' => $arFilter, - )); - return $arResult['result']; - } - - - /** - * get list of installed activities - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function getList() - { - $arResult = $this->client->call('bizproc.activity.list', - array() - ); - return $arResult['result']; - } - - /** - * delete activity - * - * @param $code string - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function delete($code) - { - $arResult = $this->client->call('bizproc.activity.delete', - array( - 'code' => $code - ) - ); - return $arResult['result']; - } - -} \ No newline at end of file diff --git a/src/classes/bizproc/Provider.php b/src/classes/bizproc/Provider.php deleted file mode 100644 index 21c0f745..00000000 --- a/src/classes/bizproc/Provider.php +++ /dev/null @@ -1,113 +0,0 @@ -client->call('bizproc.provider.add', - array( - 'CODE' => $code, - 'TYPE' => $type, - 'HANDLER' => $handler, - 'NAME' => $arName, - 'DESCRIPTION' => $arDescription - )); - - return $arResult['result']; - } - - /** - * delete provider - * - * @param $code string - * - * @see https://dev.1c-bitrix.ru/rest_help/bizproc/bizproc_provider/providerdelete.php - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function delete($code) - { - $arResult = $this->client->call('bizproc.provider.delete', - array( - 'code' => $code - ) - ); - - return $arResult['result']; - } - - /** - * get list of providers - * - * @see https://dev.1c-bitrix.ru/rest_help/bizproc/bizproc_provider/providerlist.php - * - * @return mixed - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - */ - public function getList() - { - $arResult = $this->client->call('bizproc.provider.list', - array() - ); - - return $arResult['result']; - } -} \ No newline at end of file diff --git a/src/classes/bizproc/Robot.php b/src/classes/bizproc/Robot.php deleted file mode 100644 index cdba2417..00000000 --- a/src/classes/bizproc/Robot.php +++ /dev/null @@ -1,117 +0,0 @@ -client->call( - 'bizproc.robot.add', - array( - 'CODE' => $code, - 'HANDLER' => $handler, - 'AUTH_USER_ID' => $userId, - 'NAME' => $arName, - 'PROPERTIES' => $arProps, - 'RETURN_PROPERTIES' => $arReturnProps, - 'USE_PLACEMENT' => $isUsePlacement === true ? 'Y' : 'N', - 'USE_SUBSCRIPTION' => $isUseSubscription === true ? 'Y' : 'N', - ) - ); - - return $arResult['result']; - } - - /** - * delete activity - * - * @param $code string - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @see https://dev.1c-bitrix.ru/rest_help/bizproc/bizproc_robot/robotdelete.php - * - */ - public function delete($code) - { - $arResult = $this->client->call( - 'bizproc.robot.delete', - array( - 'code' => $code, - ) - ); - - return $arResult['result']; - } - - /** - * get list of robots - * - * @see https://dev.1c-bitrix.ru/rest_help/bizproc/bizproc_robot/robotlist.php - * - * @return mixed - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - */ - public function getList() - { - $arResult = $this->client->call( - 'bizproc.robot.list', - array() - ); - - return $arResult['result']; - } -} \ No newline at end of file diff --git a/src/classes/crm/activity/activity.php b/src/classes/crm/activity/activity.php deleted file mode 100644 index f672a601..00000000 --- a/src/classes/crm/activity/activity.php +++ /dev/null @@ -1,111 +0,0 @@ -client->call( - 'crm.activity.add', - array('fields' => $fields) - ); - return $fullResult; - } - - /** - * delete activity by id - * @param integer $entityId - activity identifier - * @link http://dev.1c-bitrix.ru/rest_help/crm/rest_activity/crm_activity_delete.php - * @return array - */ - public function delete($entityId) - { - $fullResult = $this->client->call( - 'crm.activity.delete', - array('id' => $entityId) - ); - return $fullResult; - } - - /** - * get list of activity fields with description - * @link http://dev.1c-bitrix.ru/rest_help/crm/rest_activity/crm_activity_fields.php - * @return array - */ - public function fields() - { - $fullResult = $this->client->call( - 'crm.activity.fields' - ); - return $fullResult; - } - - /** - * get activity by id - * @param integer $entityId - activity identifier - * @link http://dev.1c-bitrix.ru/rest_help/crm/rest_activity/crm_activity_get.php - * @return array - */ - public function get($entityId) - { - $fullResult = $this->client->call( - 'crm.activity.get', - array('id' => $entityId) - ); - return $fullResult; - } - - /** - * Get list of activity items. - * @link http://dev.1c-bitrix.ru/rest_help/crm/rest_activity/crm_activity_list.php - * @param array $order - sort order of items - * @param array $filter - filter array - * @param array $select - array of columns to select - * @param integer $start - entity number to start from (usually returned in 'next' field of previous 'crm.activity.list' API call) - * @return array - */ - public function getList($order = array(), $filter = array(), $select = array(), $start = 0) - { - $fullResult = $this->client->call( - 'crm.activity.list', - array( - 'order' => $order, - 'filter'=> $filter, - 'select'=> $select, - 'start' => $start - ) - ); - return $fullResult; - } - - /** - * update activity by id - * @param $entityId integer - activity identifier - * @param $fields array - activity fields to update - * @link http://dev.1c-bitrix.ru/rest_help/crm/rest_activity/crm_activity_update.php - * @return array - */ - public function update($entityId, $fields) - { - $fullResult = $this->client->call( - 'crm.activity.update', - array( - 'id' => $entityId, - 'fields' => $fields - ) - ); - return $fullResult; - } - - -} - diff --git a/src/classes/crm/activity/communication.php b/src/classes/crm/activity/communication.php deleted file mode 100644 index 4b2f0430..00000000 --- a/src/classes/crm/activity/communication.php +++ /dev/null @@ -1,23 +0,0 @@ -client->call( - 'crm.activity.communication.fields' - ); - return $fullResult; - } - -} - diff --git a/src/classes/crm/additional/duplicate.php b/src/classes/crm/additional/duplicate.php deleted file mode 100644 index 96f41b74..00000000 --- a/src/classes/crm/additional/duplicate.php +++ /dev/null @@ -1,31 +0,0 @@ -client->call('crm.duplicate.findbycomm', - array( - 'type' => $communicationType, - 'values'=> $arValues, - 'entity_type'=> $entityType, - ) - ); - return $result; - } -} \ No newline at end of file diff --git a/src/classes/crm/company/company.php b/src/classes/crm/company/company.php deleted file mode 100644 index ec6b09ed..00000000 --- a/src/classes/crm/company/company.php +++ /dev/null @@ -1,119 +0,0 @@ -client->call( - 'crm.company.list', - array( - 'order' => $order, - 'filter'=> $filter, - 'select'=> $select, - 'start' => $start - ) - ); - return $fullResult; - } - - /** - * Add a new company to CRM - * @param array $fields array of fields - * @link http://www.bitrixsoft.com/rest_help/crm/company/crm_company_add.php - * @return array - * @throws Bitrix24Exception - * - */ - public function add($fields = array()) - { - $fullResult = $this->client->call( - 'crm.company.add', - array('fields' => $fields) - ); - return $fullResult; - } - - /** - * Updates the specified (existing) company. - * @param array $bitrix24CompanyId integer - * @param array $fields array of fields - * @link http://www.bitrixsoft.com/rest_help/crm/company/crm_company_add.php - * @return array - * @throws Bitrix24Exception - * - */ - public function update($bitrix24CompanyId, $fields = array()) - { - $fullResult = $this->client->call( - 'crm.company.update', - array( - 'id' => $bitrix24CompanyId, - 'fields' => $fields, - ) - ); - return $fullResult; - } - - /** - * Returns a company associated with the specified company ID. - * @link http://www.bitrixsoft.com/rest_help/crm/company/crm_company_get.php - * @param integer $bitrix24CompanyId company identifier - * @return array - * @throws Bitrix24Exception - */ - public function get($bitrix24CompanyId) - { - $fullResult = $this->client->call( - 'crm.company.get', - array('id' => $bitrix24CompanyId) - ); - return $fullResult; - } - - /** - * Deletes the specified company and all the associated objects. - * @link http://www.bitrixsoft.com/rest_help/crm/company/crm_company_delete.php - * @param integer $bitrix24CompanyId company identifier - * @return array - * @throws Bitrix24Exception - */ - public function delete($bitrix24CompanyId) - { - $fullResult = $this->client->call( - 'crm.company.delete', - array('id' => $bitrix24CompanyId) - ); - return $fullResult; - } - - /** - * Returns the description of the fields available to company. - * @link http://www.bitrixsoft.com/rest_help/crm/company/crm_company_fields.php - * @return array - * @throws Bitrix24Exception - */ - public function fields() - { - $fullResult = $this->client->call( - 'crm.company.fields' - ); - return $fullResult; - } -} diff --git a/src/classes/crm/contact/contact.php b/src/classes/crm/contact/contact.php deleted file mode 100644 index ded8e1d3..00000000 --- a/src/classes/crm/contact/contact.php +++ /dev/null @@ -1,119 +0,0 @@ -client->call( - 'crm.contact.list', - array( - 'order' => $order, - 'filter'=> $filter, - 'select'=> $select, - 'start' => $start - ) - ); - return $fullResult; - } - - /** - * Add a new contact to CRM - * @param array $fields array of fields - * @param array $params array of params - * @link http://dev.1c-bitrix.ru/rest_help/crm/contacts/crm_contact_add.php - * @return array - */ - public function add($fields = array(), $params = array()) - { - $fullResult = $this->client->call( - 'crm.contact.add', - array( - 'fields' => $fields, - 'params' => $params - ) - ); - return $fullResult; - } - - /** - * Get contact by identifier - * @link http://dev.1c-bitrix.ru/rest_help/crm/contacts/crm_contact_get.php - * @param integer $bitrix24UserId contact identifier - * @return array - * @throws Bitrix24Exception - */ - public function get($bitrix24UserId) - { - $fullResult = $this->client->call( - 'crm.contact.get', - array('id' => $bitrix24UserId) - ); - return $fullResult; - } - - /** - * Deletes the specified contact - * @link http://dev.1c-bitrix.ru/rest_help/crm/contacts/crm_contact_delete.php - * @param integer $bitrix24UserId contact identifier - * @return array - * @throws Bitrix24Exception - */ - public function delete($bitrix24UserId) - { - $fullResult = $this->client->call( - 'crm.contact.delete', - array('id' => $bitrix24UserId) - ); - return $fullResult; - } - - /** - * get list of contact fields with description - * @link http://dev.1c-bitrix.ru/rest_help/crm/contacts/crm_contact_fields.php - * @return array - * @throws Bitrix24Exception - */ - public function fields() - { - $fullResult = $this->client->call( - 'crm.contact.fields' - ); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/crm/contacts/crm_contact_update.php - * @param integer $contactId Specifies the contact ID - * @param array $fields An array in format array("field"=>"value"[, ...]) containing values for the fields that need to be updated. - * The fields can be one or more of those returned by crm.contact.fields. - * @param array $params Set of parameters. REGISTER_SONET_EVENT - performs registration of a change event in a contact in the Activity Stream. - * The contact's Responsible person will also receive notification. - * @return array - */ - public function update($contactId, $fields = array(), $params = array()) - { - $fullResult = $this->client->call( - 'crm.contact.update', - array( - 'id' => $contactId, - 'fields' => $fields, - 'params' => $params - ) - ); - return $fullResult; - } -} diff --git a/src/classes/crm/contact/userfield.php b/src/classes/crm/contact/userfield.php deleted file mode 100644 index 88803309..00000000 --- a/src/classes/crm/contact/userfield.php +++ /dev/null @@ -1,97 +0,0 @@ -client->call( - 'crm.contact.userfield.list', - array( - 'order' => $order, - 'filter'=> $filter - ) - ); - return $fullResult; - } - - /** - * Get item userfield - * @link http://dev.1c-bitrix.ru/rest_help/crm/contacts/crm_contact_userfield_get.php - * @param integer $userfieldId - contact userfield id - * @return array - */ - public function get($userfieldId) - { - $fullResult = $this->client->call( - 'crm.contact.userfield.get', - array('id' => $userfieldId) - ); - return $fullResult; - } - - /** - * Delete userfield - * @link http://dev.1c-bitrix.ru/rest_help/crm/contacts/crm_contact_userfield_delete.php - * @param integer $userfieldId - contact userfield id - * @return array - */ - public function delete($userfieldId) - { - $fullResult = $this->client->call( - 'crm.contact.userfield.delete', - array('id' => $userfieldId) - ); - return $fullResult; - } - - /** - * Add a new userfield to contact - * @param array $fields array of fields - * @link http://dev.1c-bitrix.ru/rest_help/crm/contacts/crm_contact_userfield_add.php - * @return array - */ - public function add($fields = array()) - { - $fullResult = $this->client->call( - 'crm.contact.userfield.add', - array('fields' => $fields) - ); - return $fullResult; - } - - - /** - * Updates userfield - * - * @param $id - * @param array $fields - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/contacts/crm_contact_userfield_update.php - * @return array - */ - public function update($id, $fields = array()) - { - $fullResult = $this->client->call( - 'crm.contact.userfield.update', - array( - 'id' => $id, - 'fields' => $fields - ) - ); - - return $fullResult; - } -} diff --git a/src/classes/crm/deal/category.php b/src/classes/crm/deal/category.php deleted file mode 100644 index 54045ac0..00000000 --- a/src/classes/crm/deal/category.php +++ /dev/null @@ -1,261 +0,0 @@ -client->call( - 'crm.dealcategory.add', - array( - 'fields' => $fields, - 'params' => $params - ) - ); - return $fullResult; - } - - /** - * delete deal by id - * - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_dealcategory_delete.php - * @var $id integer deal identifier - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - */ - public function delete($id) - { - $fullResult = $this->client->call( - 'crm.dealcategory.delete', - array('id' => $id) - ); - return $fullResult; - } - - /** - * get list of deal fields with description - * - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_dealcategory_fields.php - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - */ - public function fields() - { - $fullResult = $this->client->call( - 'crm.dealcategory.fields' - ); - return $fullResult; - } - - /** - * get deal by id - * - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_dealcategory_get.php - * @var $dealId integer deal identifier - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - */ - public function get($dealId) - { - $fullResult = $this->client->call( - 'crm.dealcategory.get', - array('id' => $dealId) - ); - return $fullResult; - } - - /** - * get default category - * - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_dealcategory_default_get.php - * @var $dealId integer deal identifier - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - */ - public function getDefault() - { - $fullResult = $this->client->call( - 'crm.dealcategory.default.get' - ); - return $fullResult; - } - - /** - * update default category fields - * - * @param $fields - * @param array $params Set of parameters. REGISTER_SONET_EVENT - performs registration of a change event in - * a deal in the Activity Stream. The deals's Responsible person will also receive - * notification. - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_dealcategory_default_set.php - */ - public function setDefault($fields, $params = array()) - { - $fullResult = $this->client->call( - 'crm.dealcategory.default.set', - array( - 'fields' => $fields, - 'params' => $params - ) - ); - return $fullResult; - } - - /** - * Get list of deal items. - * - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_dealcategory_list.php - * - * @param array $order - order of deal items - * @param array $filter - filter array - * @param array $select - array of collumns to select - * @param integer $start - entity number to start from (usually returned in 'next' field of previous - * 'crm.dealcategory.list' API call) - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - */ - public function getList($order = array(), $filter = array(), $select = array(), $start = 0) - { - $fullResult = $this->client->call( - 'crm.dealcategory.list', - array( - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'start' => $start - ) - ); - return $fullResult; - } - - /** - * update deal by id - * - * @param integer $dealId integer deal identifier - * @param array $dealFields array deal fields to update - * @param array $params Set of parameters. REGISTER_SONET_EVENT - performs registration of a change event in - * a deal in the Activity Stream. The deals's Responsible person will also receive - * notification. - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_dealcategory_update.php - */ - public function update($dealId, $dealFields, $params = array()) - { - $fullResult = $this->client->call( - 'crm.dealcategory.update', - array( - 'id' => $dealId, - 'fields' => $dealFields, - 'params' => $params - ) - ); - return $fullResult; - } -} diff --git a/src/classes/crm/deal/deal.php b/src/classes/crm/deal/deal.php deleted file mode 100644 index 96de0c3c..00000000 --- a/src/classes/crm/deal/deal.php +++ /dev/null @@ -1,117 +0,0 @@ -client->call( - 'crm.deal.add', - array( - 'fields' => $fields, - 'params' => $params - ) - ); - return $fullResult; - } - - /** - * delete deal by id - * @var $dealId integer deal identifier - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_delete.php - * @return array - */ - public function delete($dealId) - { - $fullResult = $this->client->call( - 'crm.deal.delete', - array('id' => $dealId) - ); - return $fullResult; - } - - /** - * get list of deal fields with description - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_fields.php - * @return array - */ - public function fields() - { - $fullResult = $this->client->call( - 'crm.deal.fields' - ); - return $fullResult; - } - - /** - * get deal by id - * @var $dealId integer deal identifier - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_get.php - * @return array - */ - public function get($dealId) - { - $fullResult = $this->client->call( - 'crm.deal.get', - array('id' => $dealId) - ); - return $fullResult; - } - - /** - * Get list of deal items. - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_list.php - * @param array $order - order of deal items - * @param array $filter - filter array - * @param array $select - array of collumns to select - * @param integer $start - entity number to start from (usually returned in 'next' field of previous 'crm.deal.list' API call) - * @return array - */ - public function getList($order = array(), $filter = array(), $select = array(), $start = 0) - { - $fullResult = $this->client->call( - 'crm.deal.list', - array( - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'start' => $start - ) - ); - return $fullResult; - } - - /** - * update deal by id - * @param integer $dealId integer deal identifier - * @param array $dealFields array deal fields to update - * @param array $params Set of parameters. REGISTER_SONET_EVENT - performs registration of a change event in a deal in the Activity Stream. - * The deals's Responsible person will also receive notification. - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_update.php - * @return array - */ - public function update($dealId, $dealFields, $params = array()) - { - $fullResult = $this->client->call( - 'crm.deal.update', - array( - 'id' => $dealId, - 'fields' => $dealFields, - 'params' => $params - ) - ); - return $fullResult; - } - - -} diff --git a/src/classes/crm/deal/productrows.php b/src/classes/crm/deal/productrows.php deleted file mode 100644 index af35edf3..00000000 --- a/src/classes/crm/deal/productrows.php +++ /dev/null @@ -1,46 +0,0 @@ -client->call( - 'crm.deal.productrows.get', - array( - 'id' => $id - ) - ); - return $fullResult; - } - - /** - * Set deal products. - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_productrows_set.php - * @param int $id - deal id - * @param array $rows - products data - * @return array - */ - public function set($id, $rows) - { - $fullResult = $this->client->call( - 'crm.deal.productrows.set', - array( - 'id' => $id, - 'rows' => $rows - ) - ); - return $fullResult; - } -} diff --git a/src/classes/crm/deal/userfield.php b/src/classes/crm/deal/userfield.php deleted file mode 100644 index eb6ecc11..00000000 --- a/src/classes/crm/deal/userfield.php +++ /dev/null @@ -1,112 +0,0 @@ -client->call( - 'crm.deal.userfield.list', - array( - 'order' => $order, - 'filter' => $filter, - ) - ); - - return $fullResult; - } - - /** - * Get item userfield - * - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_userfield_get.php - * - * @param integer $userfieldId - deal userfield id - * - * @return array - */ - public function get($userfieldId) - { - $fullResult = $this->client->call( - 'crm.deal.userfield.get', - array('id' => $userfieldId) - ); - - return $fullResult; - } - - /** - * Delete userfield - * - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_userfield_delete.php - * - * @param integer $userfieldId - deal userfield id - * - * @return array - */ - public function delete($userfieldId) - { - $fullResult = $this->client->call( - 'crm.deal.userfield.delete', - array('id' => $userfieldId) - ); - - return $fullResult; - } - - /** - * Add a new userfield to deal - * - * @param array $fields array of fields - * - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_userfield_add.php - * @return array - */ - public function add($fields = array()) - { - $fullResult = $this->client->call( - 'crm.deal.userfield.add', - array('fields' => $fields) - ); - - return $fullResult; - } - - /** - * Add a new userfield to deal - * - * @param int $userfieldId deal userfield id - * @param array $fields array of fields - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_userfield_update.php - * @return array - */ - public function update($userfieldId, $fields = array()) - { - $fullResult = $this->client->call( - 'crm.deal.userfield.update', - array( - 'id' => $userfieldId, - 'fields' => $fields, - ) - ); - - return $fullResult; - } -} \ No newline at end of file diff --git a/src/classes/crm/enum/enum.php b/src/classes/crm/enum/enum.php deleted file mode 100644 index 40638697..00000000 --- a/src/classes/crm/enum/enum.php +++ /dev/null @@ -1,109 +0,0 @@ -client->call( - 'crm.enum.fields' - ); - return $fullResult; - } - - - - /** - * get list of enum owner types - * @link http://dev.1c-bitrix.ru/rest_help/crm/auxiliary/enum/crm_enum_ownertype.php - * @return array - */ - public function ownerType() - { - $fullResult = $this->client->call( - 'crm.enum.ownertype' - ); - return $fullResult; - } - - /** - * get list of enum activity types - * @link http://dev.1c-bitrix.ru/rest_help/crm/auxiliary/enum/crm_enum_activitytype.php - * @return array - */ - public function activityType() - { - $fullResult = $this->client->call( - 'crm.enum.activitytype' - ); - return $fullResult; - } - - - /** - * get list of enum activity priorities - * @link http://dev.1c-bitrix.ru/rest_help/crm/auxiliary/enum/crm_enum_activitypriority.php - * @return array - */ - public function activityPriority() - { - $fullResult = $this->client->call( - 'crm.enum.activitypriority' - ); - return $fullResult; - } - - - /** - * get list of enum content types - * @link http://dev.1c-bitrix.ru/rest_help/crm/auxiliary/enum/crm_enum_contenttype.php - * @return array - */ - public function contentType() - { - $fullResult = $this->client->call( - 'crm.enum.contenttype' - ); - return $fullResult; - } - - - /** - * get list of enum activity directions - * @link http://dev.1c-bitrix.ru/rest_help/crm/auxiliary/enum/crm_enum-activitydirection.php - * @return array - */ - public function activityDirection() - { - $fullResult = $this->client->call( - 'crm.enum.activitydirection' - ); - return $fullResult; - } - - - /** - * get list of enum activity notify types - * @link http://dev.1c-bitrix.ru/rest_help/crm/auxiliary/enum/crm_enumactivitynotifytype.php - * @return array - */ - public function activityNotifyType() - { - $fullResult = $this->client->call( - 'crm.enum.activitynotifytype' - ); - return $fullResult; - } - - -} - - diff --git a/src/classes/crm/invoice/invoice.php b/src/classes/crm/invoice/invoice.php deleted file mode 100644 index ff024aba..00000000 --- a/src/classes/crm/invoice/invoice.php +++ /dev/null @@ -1,232 +0,0 @@ -client->call( - 'crm.invoice.list', - array( - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'start' => $start - ) - ); - return $fullResult; - } - - /** - * get invoice by id - * - * @link http://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_invoice_get.php - * @var $invoiceId integer invoice identifier - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException -*/ - public function get($invoiceId) - { - $fullResult = $this->client->call( - 'crm.invoice.get', - array('id' => $invoiceId) - ); - return $fullResult; - } - - /** - * delete invoice by id - * - * @link http://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_invoice_delete.php - * @var $invoiceId integer invoice identifier - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException -*/ - public function delete($invoiceId) - { - $fullResult = $this->client->call( - 'crm.invoice.delete', - array('id' => $invoiceId) - ); - return $fullResult; - } - - /** - * Add a new invoice to CRM - * - * @param array $fields array of fields - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @link http://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_invoice_add.php -*/ - public function add($fields = array()) - { - $fullResult = $this->client->call( - 'crm.invoice.add', - array('fields' => $fields) - ); - return $fullResult; - } - - /** - * update invoice by id - * - * @link http://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_invoice_update.php - * - * @param $invoiceId - * @param $invoiceFields - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException -*/ - public function update($invoiceId, $invoiceFields) - { - $fullResult = $this->client->call( - 'crm.invoice.update', - array( - 'id' => $invoiceId, - 'fields' => $invoiceFields - ) - ); - return $fullResult; - } - - /** - * get list of invoice fields with description - * - * @link http://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_invoice_fields.php - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException -*/ - public function fields() - { - $fullResult = $this->client->call( - 'crm.invoice.fields' - ); - return $fullResult; - } - - /** - * get external link for invoice - * - * @param $id - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - */ - public function getExternalLink($id) - { - $fullResult = $this->client->call( - 'crm.invoice.getexternallink', - array( - 'id' => $id - ) - ); - return $fullResult; - } -} diff --git a/src/classes/crm/invoice/paysystem.php b/src/classes/crm/invoice/paysystem.php deleted file mode 100644 index b3d8927b..00000000 --- a/src/classes/crm/invoice/paysystem.php +++ /dev/null @@ -1,75 +0,0 @@ -client->call( - 'crm.paysystem.list', - array( - 'order' => $order, - 'filter' => $filter, - ) - ); - - return $fullResult; - } - - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_paysystem_fields.php - * - * @return array - * - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * - */ - public function fields() - { - $fullResult = $this->client->call( - 'crm.paysystem.fields', - array() - ); - - return $fullResult; - } -} \ No newline at end of file diff --git a/src/classes/crm/invoice/persontype.php b/src/classes/crm/invoice/persontype.php deleted file mode 100644 index a6090ffb..00000000 --- a/src/classes/crm/invoice/persontype.php +++ /dev/null @@ -1,75 +0,0 @@ -client->call( - 'crm.persontype.list', - array( - 'order' => $order, - 'filter' => $filter, - ) - ); - - return $fullResult; - } - - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_persontype_fields.php - * - * @return array - * - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * - */ - public function fields() - { - $fullResult = $this->client->call( - 'crm.persontype.fields', - array() - ); - - return $fullResult; - } -} \ No newline at end of file diff --git a/src/classes/crm/invoice/status.php b/src/classes/crm/invoice/status.php deleted file mode 100644 index 5b3c116c..00000000 --- a/src/classes/crm/invoice/status.php +++ /dev/null @@ -1,76 +0,0 @@ -client->call( - 'crm.invoice.status.list', - array( - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'start' => $start - ) - ); - return $fullResult; - } - - /** - * get by id - * - * @link http://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_invoice_status_get.php - * - * @param integer $invoiceStatusId - invoice status identifier - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException -*/ - public function get($invoiceStatusId) - { - $fullResult = $this->client->call( - 'crm.invoice.status.get', - array('id' => $invoiceStatusId) - ); - return $fullResult; - } - -} - diff --git a/src/classes/crm/invoice/userfield.php b/src/classes/crm/invoice/userfield.php deleted file mode 100644 index d4f08bd2..00000000 --- a/src/classes/crm/invoice/userfield.php +++ /dev/null @@ -1,172 +0,0 @@ -client->call( - 'crm.invoice.userfield.list', - array( - 'order' => $order, - 'filter' => $filter, - ) - ); - - return $fullResult; - } - - /** - * Get item userfield - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_invoice_userfield_get.php - * - * @param integer $userfieldId - invoice userfield id - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - */ - public function get($userfieldId) - { - $fullResult = $this->client->call( - 'crm.invoice.userfield.get', - array('id' => $userfieldId) - ); - - return $fullResult; - } - - /** - * Delete userfield - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_invoice_userfield_delete.php - * - * @param integer $userfieldId - invoice userfield id - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - */ - public function delete($userfieldId) - { - $fullResult = $this->client->call( - 'crm.invoice.userfield.delete', - array('id' => $userfieldId) - ); - - return $fullResult; - } - - /** - * Add a new userfield to invoice - * - * @param array $fields array of fields - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @link https://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_invoice_userfield_add.php - */ - public function add($fields = array()) - { - $fullResult = $this->client->call( - 'crm.invoice.userfield.add', - array('fields' => $fields) - ); - - return $fullResult; - } - - /** - * Update a new userfield to invoice - * - * @param int $userfieldId invoice userfield id - * @param array $fields array of fields - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @link https://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_invoice_userfield_update.php - */ - public function update($userfieldId, $fields = array()) - { - $fullResult = $this->client->call( - 'crm.invoice.userfield.update', - array( - 'id' => $userfieldId, - 'fields' => $fields, - ) - ); - - return $fullResult; - } -} \ No newline at end of file diff --git a/src/classes/crm/lead/lead.php b/src/classes/crm/lead/lead.php deleted file mode 100644 index b2d63009..00000000 --- a/src/classes/crm/lead/lead.php +++ /dev/null @@ -1,113 +0,0 @@ -client->call( - 'crm.lead.get', - array('id' => $leadId) - ); - return $fullResult; - } - - /** - * Get list of lead items. - * @link http://dev.1c-bitrix.ru/rest_help/crm/leads/crm_lead_list.php - * @param array $order - order of task items - * @param array $filter - filter array - * @param array $select - array of collumns to select - * @param integer $start - entity number to start from (usually returned in 'next' field of previous 'crm.lead.list' API call) - * @return array - */ - public function getList($order = array(), $filter = array(), $select = array(), $start = 0) - { - $fullResult = $this->client->call( - 'crm.lead.list', - array( - 'order' => $order, - 'filter'=> $filter, - 'select'=> $select, - 'start' => $start - ) - ); - return $fullResult; - } - - /** - * Add a new lead to CRM - * @param array $fields array of fields - * @param array $params Set of parameters. REGISTER_SONET_EVENT - performs registration of a change event in a lead in the Activity Stream. - * The lead's Responsible person will also receive notification. - * @link http://dev.1c-bitrix.ru/rest_help/crm/leads/crm_lead_add.php - * @return array - */ - public function add($fields = array(), $params = array()) - { - $fullResult = $this->client->call( - 'crm.lead.add', - array( - 'fields' => $fields, - 'params' => $params - ) - ); - return $fullResult; - } - - /** - * get list of lead fields with description - * @link http://dev.1c-bitrix.ru/rest_help/crm/leads/crm_lead_fields.php - * @return array - */ - public function fields() - { - $fullResult = $this->client->call( - 'crm.lead.fields' - ); - return $fullResult; - } - - /** - * @link https://training.bitrix24.com/rest_help/crm/leads/crm_lead_update.php - * @param integer $leadId Specifies the lead ID - * @param array $fields An array in format array("field"=>"value"[, ...]) containing values for the fields that need to be updated. - * The fields can be one or more of those returned by crm.lead.fields. - * @param array $params Set of parameters. REGISTER_SONET_EVENT - performs registration of a change event in a lead in the Activity Stream. - * The lead's Responsible person will also receive notification. - * @return array - */ - public function update($leadId, $fields = array(), $params = array()) - { - $fullResult = $this->client->call( - 'crm.lead.update', - array( - 'id' => $leadId, - 'fields' => $fields, - 'params' => $params - ) - ); - return $fullResult; - } - - /** - * Deletes the specified lead and all the associated objects. - * @param integer $leadId - * @return array - */ - public function delete($leadId) - { - $fullResult = $this->client->call( - 'crm.lead.delete', - array('id' => $leadId) - ); - return $fullResult; - } -} diff --git a/src/classes/crm/lead/productrows.php b/src/classes/crm/lead/productrows.php deleted file mode 100644 index 54b8c57e..00000000 --- a/src/classes/crm/lead/productrows.php +++ /dev/null @@ -1,45 +0,0 @@ -client->call( - 'crm.lead.productrows.get', - array( - 'id' => $id - ) - ); - return $fullResult; - } - - /** - * Set lead products. - * @link https://dev.1c-bitrix.ru/rest_help/crm/leads/crm_lead_productrows_set.php - * @param int $id - lead id - * @param array $rows - products data - * @return array - */ - public function set($id, $rows) - { - $fullResult = $this->client->call( - 'crm.lead.productrows.set', - array( - 'id' => $id, - 'rows' => $rows - ) - ); - return $fullResult; - } -} diff --git a/src/classes/crm/lead/userfield.php b/src/classes/crm/lead/userfield.php deleted file mode 100644 index 60eab52e..00000000 --- a/src/classes/crm/lead/userfield.php +++ /dev/null @@ -1,108 +0,0 @@ -client->call( - 'crm.lead.userfield.list', - array( - 'order' => $order, - 'filter'=> $filter - ) - ); - return $fullResult; - } - - /** - * Get item userfield - * @link http://dev.1c-bitrix.ru/rest_help/crm/leads/crm_lead_userfield_get.php - * @param integer $userfieldId - lead userfield id - * @return array - */ - public function get($userfieldId) - { - $fullResult = $this->client->call( - 'crm.lead.userfield.get', - array('id' => $userfieldId) - ); - return $fullResult; - } - - /** - * delete userfield - * @link http://dev.1c-bitrix.ru/rest_help/crm/leads/crm_lead_userfield_delete.php - * @param integer $userfieldId - lead userfield id - * @return array - */ - public function delete($userfieldId) - { - $fullResult = $this->client->call( - 'crm.lead.userfield.delete', - array('id' => $userfieldId) - ); - return $fullResult; - } - - /** - * get list of lead userfield fields with description - * @link http://dev.1c-bitrix.ru/rest_help/crm/leads/crm_lead_userfield_fields.php - * @return array - */ - public function fields() - { - $fullResult = $this->client->call( - 'crm.userfield.fields' - ); - return $fullResult; - } - - /** - * Add a new userfield to lead - * @param array $fields array of fields - * @link http://dev.1c-bitrix.ru/rest_help/crm/leads/crm_lead_userfield_add.php - * @return array - */ - public function add($fields = array()) - { - $fullResult = $this->client->call( - 'crm.lead.userfield.add', - array('fields' => $fields) - ); - return $fullResult; - } - - /** - * Updates userfield - * - * @param $id - * @param array $fields - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/leads/crm_lead_userfield_update.php - * @return array - */ - public function update($id, $fields = array()) - { - $fullResult = $this->client->call( - 'crm.lead.userfield.update', - array( - 'id' => $id, - 'fields' => $fields - ) - ); - - return $fullResult; - } -} \ No newline at end of file diff --git a/src/classes/crm/livefeedmessage/livefeedmessage.php b/src/classes/crm/livefeedmessage/livefeedmessage.php deleted file mode 100644 index fe8e6bff..00000000 --- a/src/classes/crm/livefeedmessage/livefeedmessage.php +++ /dev/null @@ -1,35 +0,0 @@ -client->call( - 'crm.livefeedmessage.add', - array('fields' => array( - "POST_TITLE" => $postTitle, - "MESSAGE" => $message, - "SPERM" => $sperm, - "ENTITYTYPEID" => $entityTypeId, - "ENTITYID" => $entityId - )) - ); - return $fullResult; - } -} \ No newline at end of file diff --git a/src/classes/crm/product/product.php b/src/classes/crm/product/product.php deleted file mode 100644 index d3e75852..00000000 --- a/src/classes/crm/product/product.php +++ /dev/null @@ -1,123 +0,0 @@ -client->call( - 'crm.product.list', - array( - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'start' => $start, - ) - ); - - return $fullResult; - } - - /** - * get list of product fields with description - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/products/crm_product_fields.php - * - * @return array - */ - public function fields() - { - return $this->client->call( - 'crm.product.fields' - ); - } - - /** - * get product by id - * - * @link http://dev.1c-bitrix.ru/rest_help/crm/products/crm_product_get.php - * - * @param integer $productId - product item identifier - * - * @return array - */ - public function get($productId) - { - $fullResult = $this->client->call( - 'crm.product.get', - array('id' => $productId) - ); - - return $fullResult; - } - - /** - * delete product by id - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/products/crm_product_delete.php - * - * @param integer $productId - product item identifier - * - * @return array - */ - public function delete($productId) - { - $fullResult = $this->client->call( - 'crm.product.delete', - array('id' => $productId) - ); - - return $fullResult; - } - - /** - * @param $productId - * @param array $arFields - * - * @return array - */ - public function update($productId, array $arFields) - { - return $this->client->call('crm.product.update', array( - 'id' => $productId, - 'fields' => $arFields, - )); - } - - /** - * add new product - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/products/crm_product_add.php - * - * @param $arNewProduct - * - * @return array - */ - public function add($arNewProduct) - { - $fullResult = $this->client->call( - 'crm.product.add', - array('fields' => $arNewProduct) - ); - - return $fullResult; - } -} - - diff --git a/src/classes/crm/product/property.php b/src/classes/crm/product/property.php deleted file mode 100644 index ea939457..00000000 --- a/src/classes/crm/product/property.php +++ /dev/null @@ -1,136 +0,0 @@ -client->call( - 'crm.product.property.get', - array('id' => $productPropertyId) - ); - - return $fullResult; - } - - /** - * delete product property by id - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/products/crm_product_property_delete.php - * - * @param integer $productPropertyId - product property identifier - * - * @return array - * @throws Bitrix24Exception - */ - public function delete($productPropertyId) - { - $fullResult = $this->client->call( - 'crm.product.property.delete', - array('id' => $productPropertyId) - ); - - return $fullResult; - } - - /** - * get product property list - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/products/crm_product_property_list.php - * - * @param array $order - * @param array $filter - * - * @return array - * @throws Bitrix24Exception - */ - public function getList($order = array(), $filter = array()) - { - $fullResult = $this->client->call( - 'crm.product.property.list', - array( - 'order' => $order, - 'filter' => $filter, - ) - ); - - return $fullResult; - } - - /** - * add product property - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/products/crm_product_property_list.php - * - * @param array $fields - * - * @return array - * @throws Bitrix24Exception - */ - public function add(array $fields) - { - $fullResult = $this->client->call( - 'crm.product.property.add', - array( - 'fields' => $fields, - ) - ); - - return $fullResult; - } - - /** - * update product property - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/products/crm_product_property_update.php - * - * @param int $productPropertyId - * @param array $fields - * - * @return array - * @throws Bitrix24Exception - */ - public function update($productPropertyId, array $fields) - { - $fullResult = $this->client->call( - 'crm.product.property.add', - array( - 'id' => $productPropertyId, - 'fields' => $fields, - ) - ); - - return $fullResult; - } - - /** - * get property types - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/products/crm_product_property_types.php - * @return array - * @throws Bitrix24Exception - */ - public function getTypes() - { - return $this->client->call('crm.product.property.types'); - } -} \ No newline at end of file diff --git a/src/classes/crm/productrow/productrow.php b/src/classes/crm/productrow/productrow.php deleted file mode 100644 index e22111f1..00000000 --- a/src/classes/crm/productrow/productrow.php +++ /dev/null @@ -1,49 +0,0 @@ -client->call( - 'crm.productrow.list', - array( - 'order' => array(), - 'filter'=> array( - 'OWNER_TYPE'=> $ownerType, - 'OWNER_ID'=> $ownerId, - ), - 'select'=> array(), - 'start' => $start - ) - ); - return $fullResult; - } - - - /** - * get fields descriptions - * @link http://dev.1c-bitrix.ru/rest_help/crm/productrow/crm_productrow_fields.php - * @return array - */ - public function fields() - { - $fullResult = $this->client->call( - 'crm.productrow.fields', - array() - ); - return $fullResult; - } - -} - - diff --git a/src/classes/crm/productsection/productsection.php b/src/classes/crm/productsection/productsection.php deleted file mode 100644 index 7fe8e199..00000000 --- a/src/classes/crm/productsection/productsection.php +++ /dev/null @@ -1,197 +0,0 @@ -client->call( - 'crm.productsection.list', - array( - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'start' => $start, - ) - ); - - return $fullResult; - } - - /** - * get list of product fields with description - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/product_section/crm_productsection_fields.php - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - */ - public function fields() - { - return $this->client->call( - 'crm.productsection.fields' - ); - } - - /** - * get product by id - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/product_section/crm_productsection_get.php - * - * @param integer $id - product item identifier - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - */ - public function get($id) - { - $fullResult = $this->client->call( - 'crm.productsection.get', - array('id' => $id) - ); - - return $fullResult; - } - - /** - * delete product by id - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/product_section/crm_productsection_delete.php - * - * @param integer $id - product item identifier - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - */ - public function delete($id) - { - $fullResult = $this->client->call( - 'crm.productsection.delete', - array('id' => $id) - ); - - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/product_section/crm_productsection_update.php - * - * @param $id - * @param array $arFields - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - */ - public function update($id, array $arFields) - { - return $this->client->call('crm.productsection.update', array( - 'id' => $id, - 'fields' => $arFields, - )); - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/product_section/crm_productsection_add.php - * - * @param $arProductSection - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - */ - public function add($arProductSection) - { - $fullResult = $this->client->call( - 'crm.productsection.add', - array('fields' => $arProductSection) - ); - - return $fullResult; - } -} - - - diff --git a/src/classes/crm/quote/quote.php b/src/classes/crm/quote/quote.php deleted file mode 100644 index 2cdaa682..00000000 --- a/src/classes/crm/quote/quote.php +++ /dev/null @@ -1,106 +0,0 @@ -client->call( - 'crm.quote.list', - array( - 'order' => $order, - 'filter'=> $filter, - 'select'=> $select, - 'start' => $start - ) - ); - return $fullResult; - } - - /** - * get quote by id - * @var $quoteId integer quote identifier - * @link http://dev.1c-bitrix.ru/rest_help/crm/quote/crm_quote_get.php - * @return array - */ - public function get($quoteId) - { - $fullResult = $this->client->call( - 'crm.quote.get', - array('id' => $quoteId) - ); - return $fullResult; - } - - /** - * delete quote by id - * @var $quoteId integer quote identifier - * @link http://dev.1c-bitrix.ru/rest_help/crm/quote/crm_quote_delete.php - * @return array - */ - public function delete($quoteId) - { - $fullResult = $this->client->call( - 'crm.quote.delete', - array('id' => $quoteId) - ); - return $fullResult; - } - - /** - * Add a new quote to CRM - * @param array $fields array of fields - * @link http://dev.1c-bitrix.ru/rest_help/crm/quote/crm_quote_add.php - * @return array - */ - public function add($fields = array()) - { - $fullResult = $this->client->call( - 'crm.quote.add', - array('fields' => $fields) - ); - return $fullResult; - } - - /** - * update quote by id - * @var $quoteId integer quote identifier - * @var $quoteFields array quote fields to update - * @link http://dev.1c-bitrix.ru/rest_help/crm/quote/crm_quote_update.php - * @return array - */ - public function update($quoteId, $quoteFields) - { - $fullResult = $this->client->call( - 'crm.quote.update', - array( - 'id' => $quoteId, - 'fields' => $quoteFields - ) - ); - return $fullResult; - } - - /** - * get list of quote fields with description - * @link http://dev.1c-bitrix.ru/rest_help/crm/quote/crm_quote_fields.php - * @return array - */ - public function fields() - { - $fullResult = $this->client->call( - 'crm.quote.fields' - ); - return $fullResult; - } -} diff --git a/src/classes/crm/requisite/address.php b/src/classes/crm/requisite/address.php deleted file mode 100644 index 34b4a1ae..00000000 --- a/src/classes/crm/requisite/address.php +++ /dev/null @@ -1,131 +0,0 @@ -client->call( - 'crm.address.add', - array( - 'fields' => $fields, - ) - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_address_delete.php - * - * @param array $fields array of fields - * - * @return array - * @throws Bitrix24Exception - */ - public function delete($fields) - { - $fullResult = $this->client->call( - 'crm.address.delete', - array('fields' => $fields) - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_address_fields.php - * @return array - * @throws Bitrix24Exception - */ - public function fields() - { - $fullResult = $this->client->call( - 'crm.address.fields' - ); - return $fullResult; - } - - - /** - * Get list of requisite items. - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_address_list.php - * - * @param array $order - order of items - * @param array $filter - filter array - * @param array $select - array of collumns to select - * @param integer $start - entity number to start from (usually returned in 'next' field of previous - * 'crm.contact.list' API call) - * - * @return array - * @throws Bitrix24Exception - * - */ - public function getList($order = array(), $filter = array(), $select = array(), $start = 0) - { - $fullResult = $this->client->call( - 'crm.address.list', - array( - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'start' => $start - ) - ); - return $fullResult; - } - - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_address_update.php - * - * @param array $fields An array in format array("field"=>"value"[, ...]) containing values for the fields - * that need to be updated. The fields can be one or more of those returned by - * crm.contact.fields. - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function update($fields = array()) - { - $fullResult = $this->client->call( - 'crm.address.update', - array( - 'fields' => $fields - ) - ); - return $fullResult; - } -} diff --git a/src/classes/crm/requisite/bank.php b/src/classes/crm/requisite/bank.php deleted file mode 100644 index 2033658a..00000000 --- a/src/classes/crm/requisite/bank.php +++ /dev/null @@ -1,148 +0,0 @@ -client->call( - 'crm.requisite.bankdetail.add', - array( - 'fields' => $fields, - ) - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_bankdetail_delete.php - * - * @param integer $id of bank requisite - * - * @return array - * @throws Bitrix24Exception - */ - public function delete($id) - { - $fullResult = $this->client->call( - 'crm.requisite.bankdetail.delete', - array('id' => $id) - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_bankdetail_fields.php - * @return array - * @throws Bitrix24Exception - */ - public function fields() - { - $fullResult = $this->client->call( - 'crm.requisite.bankdetail.fields' - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_bankdetail_get.php - * - * @param integer $id of bank requisite - * - * @return array - * @throws Bitrix24Exception - */ - public function get($id) - { - $fullResult = $this->client->call( - 'crm.requisite.bankdetail.get', - array('id' => $id) - ); - return $fullResult; - } - - - /** - * Get list of requisite items. - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_bankdetail_list.php - * - * @param array $order - order of items - * @param array $filter - filter array - * @param array $select - array of collumns to select - * @param integer $start - entity number to start from (usually returned in 'next' field of previous - * 'crm.contact.list' API call) - * - * @return array - * @throws Bitrix24Exception - * - */ - public function getList($order = array(), $filter = array(), $select = array(), $start = 0) - { - $fullResult = $this->client->call( - 'crm.requisite.bankdetail.list', - array( - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'start' => $start - ) - ); - return $fullResult; - } - - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_bankdetail_update.php - * - * @param integer $id - * @param array $fields An array in format array("field"=>"value"[, ...]) containing values for the fields that - * need to be updated. The fields can be one or more of those returned by - * crm.requisite.bankdetail.fields - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function update($id, $fields = array()) - { - $fullResult = $this->client->call( - 'crm.requisite.bankdetail.update', - array( - 'id' => $id, - 'fields' => $fields, - ) - ); - return $fullResult; - } -} diff --git a/src/classes/crm/requisite/link.php b/src/classes/crm/requisite/link.php deleted file mode 100644 index 1663a69d..00000000 --- a/src/classes/crm/requisite/link.php +++ /dev/null @@ -1,143 +0,0 @@ -client->call( - 'crm.requisite.link.fields' - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_link_fields.php - * - * @param $entityTypeId (@see https://dev.1c-bitrix.ru/rest_help/crm/auxiliary/enum/crm_enum_ownertype.php) - * @param $entityId - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function get($entityTypeId, $entityId) - { - $fullResult = $this->client->call( - 'crm.requisite.link.get', - array( - 'entityTypeId' => $entityTypeId, - 'entityId' => $entityId, - ) - ); - return $fullResult; - } - - /** - * Get list of requisite items. - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_link_list.php - * - * @param array $order - order of items - * @param array $filter - filter array - * @param integer $start - entity number to start from (usually returned in 'next' field of previous - * 'crm.contact.list' API call) - * - * @return array - * @throws Bitrix24Exception - * - */ - public function getList($order = array(), $filter = array(), $start = 0) - { - $fullResult = $this->client->call( - 'crm.requisite.link.list', - array( - 'order' => $order, - 'filter' => $filter, - 'start' => $start - ) - ); - return $fullResult; - } - - - /** - * Get list of requisite items. - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_link_register.php - * - * @param $fields - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function register($fields) - { - $fullResult = $this->client->call( - 'crm.requisite.link.register', - array( - 'fields' => $fields, - ) - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_link_unregister.php - * - * @param $entityTypeId (@see https://dev.1c-bitrix.ru/rest_help/crm/auxiliary/enum/crm_enum_ownertype.php) - * @param $entityId - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function unregister($entityTypeId, $entityId) - { - $fullResult = $this->client->call( - 'crm.requisite.link.get', - array( - 'entityTypeId' => $entityTypeId, - 'entityId' => $entityId, - ) - ); - return $fullResult; - } -} diff --git a/src/classes/crm/requisite/preset.php b/src/classes/crm/requisite/preset.php deleted file mode 100644 index 18f4cf23..00000000 --- a/src/classes/crm/requisite/preset.php +++ /dev/null @@ -1,207 +0,0 @@ -client->call( - 'crm.requisite.preset.add', - array( - 'fields' => $fields, - ) - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_countries.php - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function countries() - { - $fullResult = $this->client->call( - 'crm.requisite.preset.countries' - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_delete.php - * - * @param $id - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @internal param array $fields array of fields - * - */ - public function delete($id) - { - $fullResult = $this->client->call( - 'crm.requisite.preset.delete', - array('id' => $id) - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_fields.php - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function fields() - { - $fullResult = $this->client->call( - 'crm.requisite.preset.fields' - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_get.php - * - * @param $id - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function get($id) - { - $fullResult = $this->client->call( - 'crm.requisite.preset.get', - array( - 'id' => $id - ) - ); - return $fullResult; - } - - - /** - * Get list of requisite items. - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_list.php - * - * @param array $order - order of items - * @param array $filter - filter array - * @param array $select - array of collumns to select - * @param integer $start - entity number to start from (usually returned in 'next' field of previous - * 'crm.contact.list' API call) - * - * @return array - * @throws Bitrix24Exception - * - */ - public function getList($order = array(), $filter = array(), $select = array(), $start = 0) - { - $fullResult = $this->client->call( - 'crm.requisite.preset.list', - array( - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'start' => $start - ) - ); - return $fullResult; - } - - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_update.php - * - * @param $id - * @param array $fields An array in format array("field"=>"value"[, ...]) containing values for the fields - * that need to be updated. The fields can be one or more of those returned by - * crm.requisite.preset.fields - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function update($id, $fields = array()) - { - $fullResult = $this->client->call( - 'crm.requisite.preset.update', - array( - 'id' => $id, - 'fields' => $fields - ) - ); - return $fullResult; - } -} diff --git a/src/classes/crm/requisite/presetfield.php b/src/classes/crm/requisite/presetfield.php deleted file mode 100644 index cc6a1ae4..00000000 --- a/src/classes/crm/requisite/presetfield.php +++ /dev/null @@ -1,225 +0,0 @@ -client->call( - 'crm.requisite.preset.field.add', - array( - 'preset' => $preset, - 'fields' => $fields, - ) - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_field_availabletoadd.php - * - * @param array $preset - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function availableToAdd($preset = array()) - { - $fullResult = $this->client->call( - 'crm.requisite.preset.field.availabletoadd', - array( - 'preset' => $preset, - ) - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_field_delete.php - * - * @param $id - * - * @param $preset - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @internal param array $fields array of fields - */ - public function delete($id, $preset) - { - $fullResult = $this->client->call( - 'crm.requisite.preset.field.delete', - array( - 'id' => $id, - 'preset' => $preset - ) - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_field_fields.php - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function fields() - { - $fullResult = $this->client->call( - 'crm.requisite.preset.field.fields' - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_field_get.php - * - * @param $id - * - * @param $preset - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function get($id, $preset) - { - $fullResult = $this->client->call( - 'crm.requisite.preset.field.get', - array( - 'id' => $id, - 'preset' => $preset - ) - ); - return $fullResult; - } - - - /** - * Get list of requisite items. - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_field_list.php - * - * - * @param array $preset - * @param int $start - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function getList($preset = array(), $start = 0) - { - $fullResult = $this->client->call( - 'crm.requisite.preset.field.list', - array( - 'preset' => $preset, - 'start' => $start - ) - ); - return $fullResult; - } - - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_update.php - * - * @param $id - * @param array $fields An array in format array("field"=>"value"[, ...]) containing values for the fields - * that need to be updated. The fields can be one or more of those returned by - * crm.requisite.preset.fields - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function update($preset = array(), $fields = array()) - { - $fullResult = $this->client->call( - 'crm.requisite.preset.field.update', - array( - 'preset' => $preset, - 'fields' => $fields - ) - ); - return $fullResult; - } -} diff --git a/src/classes/crm/requisite/requisite.php b/src/classes/crm/requisite/requisite.php deleted file mode 100644 index 5da88431..00000000 --- a/src/classes/crm/requisite/requisite.php +++ /dev/null @@ -1,150 +0,0 @@ -client->call( - 'crm.requisite.add', - array( - 'fields' => $fields, - ) - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_delete.php - * - * @param integer $id - * - * @return array - * @throws Bitrix24Exception - */ - public function delete($id) - { - $fullResult = $this->client->call( - 'crm.requisite.delete', - array('id' => $id) - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_fields.php - * @return array - * @throws Bitrix24Exception - */ - public function fields() - { - $fullResult = $this->client->call( - 'crm.requisite.fields' - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_get.php - * - * @param integer $id - * - * @return array - * @throws Bitrix24Exception - */ - public function get($id) - { - $fullResult = $this->client->call( - 'crm.requisite.get', - array('id' => $id) - ); - return $fullResult; - } - - - /** - * Get list of requisite items. - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_list.php - * - * @param array $order - order of items - * @param array $filter - filter array - * @param array $select - array of collumns to select - * @param integer $start - entity number to start from (usually returned in 'next' field of previous - * 'crm.requisite.list' API call) - * - * @return array - * @throws Bitrix24Exception - * - */ - public function getList($order = array(), $filter = array(), $select = array(), $start = 0) - { - $fullResult = $this->client->call( - 'crm.requisite.list', - array( - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'start' => $start - ) - ); - return $fullResult; - } - - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_update.php - * - * @param $id - * @param array $fields An array in format array("field"=>"value"[, ...]) containing values for the fields - * that need to be updated. The fields can be one or more of those returned by - * crm.requisite.fields. - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function update($id, $fields = array()) - { - $fullResult = $this->client->call( - 'crm.requisite.update', - array( - 'id' => $id, - 'fields' => $fields - ) - ); - return $fullResult; - } -} diff --git a/src/classes/crm/requisite/userfield.php b/src/classes/crm/requisite/userfield.php deleted file mode 100644 index b8c82470..00000000 --- a/src/classes/crm/requisite/userfield.php +++ /dev/null @@ -1,156 +0,0 @@ -client->call( - 'crm.requisite.userfield.add', - array('fields' => $fields) - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_userfield_delete.php - * - * @param integer $userfieldId - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function delete($userfieldId) - { - $fullResult = $this->client->call( - 'crm.requisite.userfield.delete', - array('id' => $userfieldId) - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_userfield_get.php - * - * @param integer $userfieldId - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function get($userfieldId) - { - $fullResult = $this->client->call( - 'crm.requisite.userfield.get', - array('id' => $userfieldId) - ); - return $fullResult; - } - - /** - * Get list of user fields items. - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_userfield_list.php - * - * @param array $order - order of task items - * @param array $filter - filter array - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function getList($order = array(), $filter = array()) - { - $fullResult = $this->client->call( - 'crm.requisite.userfield.list', - array( - 'order' => $order, - 'filter' => $filter - ) - ); - return $fullResult; - } - - - /** - * @param $id - * @param array $fields - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_userfield_update.php - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function update($id, $fields = array()) - { - $fullResult = $this->client->call( - 'crm.requisite.userfield.update', - array( - 'id' => $id, - 'fields' => $fields - ) - ); - - return $fullResult; - } -} diff --git a/src/classes/crm/status/status.php b/src/classes/crm/status/status.php deleted file mode 100644 index a9e7c32d..00000000 --- a/src/classes/crm/status/status.php +++ /dev/null @@ -1,245 +0,0 @@ -client->call( - 'crm.status.fields' - ); - return $fullResult; - } - - /** - * get list of dictionary types - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/auxiliary/status/crm_status_entity_types.php - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function entityTypes() - { - $fullResult = $this->client->call( - 'crm.status.entity.types' - ); - return $fullResult; - } - - /** - * get dictionary data - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/auxiliary/status/crm_status_entity_items.php - * - * @param string $entityId - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function entityItems($entityId) - { - $fullResult = $this->client->call( - 'crm.status.entity.items', - [ - 'entityId' => $entityId - ] - ); - return $fullResult; - } - - /** - * @param $fields - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/auxiliary/status/crm_status_add.php - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function add($fields) - { - $fullResult = $this->client->call( - 'crm.status.add', - [ - 'fields' => $fields - ] - ); - return $fullResult; - } - - /** - * @param $id - * @param $params - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/auxiliary/status/crm_status_delete.php - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function delete($id, $params) - { - $fullResult = $this->client->call( - 'crm.status.delete', - [ - 'id' => $id, - 'params' => $params - ] - ); - return $fullResult; - } - - /** - * @param $id - * @param $fields - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/auxiliary/status/crm_status_update.php - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function update($id, $fields) - { - $fullResult = $this->client->call( - 'crm.status.update', - [ - 'id' => $id, - 'fields' => $fields - ] - ); - return $fullResult; - } - - /** - * @param $id - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/auxiliary/status/crm_status_get.php - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function get($id) - { - $fullResult = $this->client->call( - 'crm.status.get', - [ - 'id' => $id - ] - ); - return $fullResult; - } - - /** - * @param $order - * @param $filter - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/auxiliary/status/crm_status_list.php - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function getList($order, $filter, $offset = 0) - { - $fullResult = $this->client->call( - 'crm.status.list', - [ - 'order' => $order, - 'filter' => $filter, - 'start' => $offset - ] - ); - return $fullResult; - } -} diff --git a/src/classes/departments/department.php b/src/classes/departments/department.php deleted file mode 100644 index 49978f91..00000000 --- a/src/classes/departments/department.php +++ /dev/null @@ -1,98 +0,0 @@ -client->call('department.fields'); - return $result['result']; - } - - /** - * Get filtered list of departments - * @link http://dev.1c-bitrix.ru/rest_help/departments/department_get.php - * @param $sort - * @param $order - * @param $filter - * @throws Bitrix24Exception - * @return array - */ - public function get($sort, $order, $filter) - { - $filterCode = array_keys($filter); - $filterCode = $filterCode[0]; - $filterValue = array_values($filter); - $filterValue = $filterValue[0]; - $arFilter = array(Main::SORT => $sort, Main::ORDER => $order, $filterCode => $filterValue); - $result = $this->client->call('department.get', $arFilter); - return $result; - } - - /** - * Create department. Works with user, who has rights for modify company structure - * @link http://dev.1c-bitrix.ru/rest_help/departments/department_add.php - * @param $name - * @param $sort - * @param $parent - * @param $head - * @throws Bitrix24Exception - * @return integer - */ - public function add($name, $sort, $parent, $head) - { - $result = $this->client->call('department.add', array( - Fields::NAME => $name, - Fields::SORT => $sort, - Fields::PARENT => $parent, - Fields::HEAD => $head - )); - return $result['result']; - } - - /** - * Update department. Works with user, who has rights for modify company structure - * @link http://dev.1c-bitrix.ru/rest_help/departments/department_update.php - * @param $id - required - * @param $name - required - * @param $sort - * @param $parent - * @param $head - * @throws Bitrix24Exception - * @return boolean - */ - public function update($id, $name, $sort, $parent, $head) - { - $result = $this->client->call('department.update', array( - Fields::ID => $id, - Fields::NAME => $name, - Fields::SORT => $sort, - Fields::PARENT => $parent, - Fields::HEAD => $head - )); - return $result['result']; - } - - /** - * Delete department. Works with user, who has rights for modify company structure - * @param $id integer - * @throws Bitrix24Exception - * @return boolean - */ - public function delete($id) - { - $result = $this->client->call('department.delete', array(Fields::ID => $id)); - return $result['result']; - } -} diff --git a/src/classes/entity/entity.php b/src/classes/entity/entity.php deleted file mode 100644 index f0be0f13..00000000 --- a/src/classes/entity/entity.php +++ /dev/null @@ -1,310 +0,0 @@ -client->call('entity.add', array( - "ENTITY" => $entity, - "NAME" => $name, - "ACCESS" => $access - )); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_update.php - * @param $entity - * @param $name - * @param $access - * @return array - * @throws Bitrix24Exception - */ - public function update($entity, $name, $access) - { - $fullResult = $this->client->call('entity.update', array( - "ENTITY" => $entity, - "NAME" => $name, - "ACCESS" => $access - )); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_rights.php - * @param $entity - * @param $access - * @return array - * @throws Bitrix24Exception - */ - public function rights($entity, $access) - { - $result = $this->client->call('entity.rights', array( - "ENTITY" => $entity, - "ACCESS" => $access - )); - return $result; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_get.php - * @param $entity - * @return array - * @throws Bitrix24Exception - */ - public function get($entity) - { - $fullResult = $this->client->call('entity.get', array( - "ENTITY" => $entity - )); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_delete.php - * @param $entity - * @return array - * @throws Bitrix24Exception - */ - public function delete($entity) - { - $fullResult = $this->client->call('entity.delete', array( - "ENTITY" => $entity - )); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_section_add.php - * @param $entity - * @param $name - * @param array $fields - * @return array - * @throws Bitrix24Exception - */ - public function sectionAdd($entity, $name, $fields = array()) - { - $arAdd = array( - "ENTITY" => $entity, - "NAME" => $name - ); - $arAdd = array_merge($arAdd, $fields); - $fullResult = $this->client->call('entity.section.add', $arAdd); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_section_get.php - * @param $entity - * @param array $sort - * @param array $filter - * @return array - * @throws Bitrix24Exception - */ - public function sectionGet($entity, $sort = array(), $filter = array()) - { - $fullResult = $this->client->call('entity.section.get', array( - "ENTITY" => $entity, - "SORT" => $sort, - "FILTER" => $filter - )); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_section_update.php - * @param $entity - * @param $id - * @param array $fields - * @return array - * @throws Bitrix24Exception - */ - public function sectionUpdate($entity, $id, $fields = array()) - { - $arUpdate = array( - "ENTITY" => $entity, - "ID" => $id - ); - $arUpdate = array_merge($arUpdate, $fields); - $fullResult = $this->client->call('entity.section.update', $arUpdate); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_section_delete.php - * @param $entity - * @param $id - * @return array - * @throws Bitrix24Exception - */ - public function sectionDelete($entity, $id) - { - $fullResult = $this->client->call('entity.section.delete', array( - "ENTITY" => $entity, - "ID" => $id - )); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_item_add.php - * @param $entity - * @param $name - * @param array $fields - * @return array - * @throws Bitrix24Exception - */ - public function itemAdd($entity, $name, $fields = array()) - { - $arAdd = array( - "ENTITY" => $entity, - "NAME" => $name - ); - $arAdd = array_merge($arAdd, $fields); - $fullResult = $this->client->call('entity.item.add', $arAdd); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_item_get.php - * @param $entity - * @param array $sort - * @param array $filter - * @return array - * @throws Bitrix24Exception - */ - public function itemGet($entity, $sort = array(), $filter = array()) - { - $fullResult = $this->client->call('entity.item.get', array( - "ENTITY" => $entity, - "SORT" => $sort, - "FILTER" => $filter - )); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_item_update.php - * @param $entity - * @param $id - * @param array $fields - * @return array - * @throws Bitrix24Exception - */ - public function itemUpdate($entity, $id, $fields = array()) - { - $arUpdate = array( - "ENTITY" => $entity, - "ID" => $id - ); - $arUpdate = array_merge($arUpdate, $fields); - $fullResult = $this->client->call('entity.item.update', $arUpdate); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_item_delete.php - * @param $entity - * @param $id - * @return array - * @throws Bitrix24Exception - */ - public function itemDelete($entity, $id) - { - $fullResult = $this->client->call('entity.item.delete', array( - "ENTITY" => $entity, - "ID" => $id - )); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_item_property_get.php - * @param $entity - * @param $property - * @return array - * @throws Bitrix24Exception - */ - public function itemPropertyGet($entity, $property) - { - $fullResult = $this->client->call('entity.item.property.get', array( - "ENTITY" => $entity, - "PROPERTY" => $property - )); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_item_property_add.php - * @param $entity - * @param $property - * @param $name - * @param $type - * @return array - * @throws Bitrix24Exception - */ - public function itemPropertyAdd($entity, $property, $name, $type) - { - $fullResult = $this->client->call('entity.item.property.add', array( - "ENTITY" => $entity, - "PROPERTY" => $property, - "NAME" => $name, - "TYPE" => $type, - - )); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_item_property_update.php - * @param $entity - * @param $property - * @param $property_new - * @param $name - * @param $type - * @return array - * @throws Bitrix24Exception - */ - public function itemPropertyUpdate($entity, $property, $property_new, $name, $type) - { - $fullResult = $this->client->call('entity.item.property.update', array( - "ENTITY" => $entity, - "PROPERTY" => $property, - "PROPERTY_NEW" => $property_new, - "NAME" => $name, - "TYPE" => $type, - )); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_item_property_delete.php - * @param $entity - * @param $property - * @return array - * @throws Bitrix24Exception - */ - public function itemPropertyDelete($entity, $property) - { - $fullResult = $this->client->call('entity.item.property.delete', array( - "ENTITY" => $entity, - "PROPERTY" => $property - )); - return $fullResult; - } -} \ No newline at end of file diff --git a/src/classes/event/event.php b/src/classes/event/event.php deleted file mode 100644 index 18fd9bd8..00000000 --- a/src/classes/event/event.php +++ /dev/null @@ -1,101 +0,0 @@ -getConstant(strtoupper($eventHandlerName)); - return isset($result); - } - - /** - * Get list of register events - * @return array - */ - public function get() - { - $fullResult = $this->client->call( - 'event.get', - array() - ); - return $fullResult; - } - - /** - * Get list of all supported events - * @link http://dev.1c-bitrix.ru/rest_help/general/events.php - * @return array - */ - public function getList() - { - $fullResult = $this->client->call( - 'events', - array() - ); - return $fullResult; - } - /** - * Register new event handler. Work only for user with portal administrator rights - * @link http://dev.1c-bitrix.ru/rest_help/general/event_bind.php - * @param $eventName string event handler code - * @param $handler string event handler URL - * @param $authType integer user identifier, under witch event handler was executed - * @throws Bitrix24Exception - * @return array - */ - public function bind($eventName, $handler, $authType = null) - { - if(!$this->isEventHandlerCodeValid($eventName)) - { - throw new Bitrix24Exception('eventName is invalid'); - } - if(is_null($handler)) - { - throw new Bitrix24Exception('handler URL is null'); - } - $fullResult = $this->client->call( - 'event.bind', - array( - 'event' => $eventName, - 'handler' => $handler, - 'auth_type' => $authType - ) - ); - return $fullResult; - } - - /** - * Unregister event handler. Work only for user with portal administrator rights - * @link http://dev.1c-bitrix.ru/rest_help/general/event_unbind.php - * @param $eventName - * @param $handler - * @param null $authType - * @return array - */ - public function unbind($eventName = NULL, $handler = NULL, $authType = null) - { - $fullResult = $this->client->call( - 'event.unbind', - array( - 'event' => $eventName, - 'handler' => $handler, - 'auth_type' => $authType - ) - ); - return $fullResult; - } -} \ No newline at end of file diff --git a/src/classes/event/util.php b/src/classes/event/util.php deleted file mode 100644 index 19934f32..00000000 --- a/src/classes/event/util.php +++ /dev/null @@ -1,29 +0,0 @@ - $arEvent) - { - if(($arEvent['event'] === $newEventName) && ($arEvent['handler'] === $newEventHandler)) - { - $isEventBind = true; - } - } - return $isEventBind; - } -} diff --git a/src/classes/facetracker/client.php b/src/classes/facetracker/client.php deleted file mode 100644 index e15ce5ed..00000000 --- a/src/classes/facetracker/client.php +++ /dev/null @@ -1,58 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24\FaceTracker; - -use Bitrix24\Bitrix24Entity; -use Bitrix24\Exceptions\Bitrix24Exception; - -/** - * Class Client - * - * @package Bitrix24\FaceTracker - */ -class Client extends Bitrix24Entity -{ - /** - * add client face to client library - * - * @see https://dev.1c-bitrix.ru/rest_help/faceid/face_client_add.php - * - * @param $clientPhoto string client base64 encoding photo - * - * @return array - * @throws Bitrix24Exception - */ - public function add($clientPhoto) - { - return $this->client->call('face.client.add', array('PHOTO' => $clientPhoto)); - } - - /** - * find client face in client gallery - * - * @see https://dev.1c-bitrix.ru/rest_help/faceid/face_client_identify.php - * - * @param $clientPhoto string client base64 encoding photo - * @param $isForceAdd - * - * @return array - * @throws Bitrix24Exception - */ - public function identify($clientPhoto, $isForceAdd) - { - return $this->client->call('face.client.identify', - array( - 'PHOTO' => $clientPhoto, - 'FORCE_ADD' => $isForceAdd === true ? 'Y' : 'N', - ) - ); - } -} \ No newline at end of file diff --git a/src/classes/facetracker/user.php b/src/classes/facetracker/user.php deleted file mode 100644 index 0a5f4f12..00000000 --- a/src/classes/facetracker/user.php +++ /dev/null @@ -1,79 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24\FaceTracker; - -use Bitrix24\Bitrix24Entity; -use Bitrix24\Exceptions\Bitrix24Exception; - -/** - * Class User - * - * @package Bitrix24\FaceTracker - */ -class User extends Bitrix24Entity -{ - /** - * add user face to client library - * - * @param $userId int user identifier - * @param $userPhoto string client base64 encoding photo - * - * @return array - * @throws Bitrix24Exception - */ - public function add($userId, $userPhoto) - { - return $this->client->call('face.user.add', - array( - 'PHOTO' => $userPhoto, - 'USER_ID' => $userId, - ) - ); - } - - /** - * find user face in user gallery - * - * @see https://dev.1c-bitrix.ru/rest_help/faceid/face_user_identify.php - * - * @param $clientPhoto string client base64 encoding photo - * - * @return array - * @throws Bitrix24Exception - */ - public function identify($clientPhoto) - { - return $this->client->call('face.user.identify', - array( - 'PHOTO' => $clientPhoto, - ) - ); - } - - /** - * delete face from user gallery - * - * @see https://dev.1c-bitrix.ru/rest_help/faceid/face_user_delete.php - * - * @param $faceId - * - * @return array - * @throws Bitrix24Exception - */ - public function delete($faceId) - { - return $this->client->call('face.user.delete', - array( - 'FACE_ID' => $faceId, - ) - ); - } -} \ No newline at end of file diff --git a/src/classes/im/attach/attach.php b/src/classes/im/attach/attach.php deleted file mode 100644 index 9cfa3d44..00000000 --- a/src/classes/im/attach/attach.php +++ /dev/null @@ -1,129 +0,0 @@ - and contributors - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Im\Attach; -use Bitrix24\Bitrix24Entity; -use Bitrix24\Bitrix24Exception; -use Bitrix24\Presets\Im\Fields as B24ImFields; -use Bitrix24\Im\Attach\iAttachItem; - -/** - * Class Attach - * @package Bitrix24\Im\Attach - */ -class Attach implements iAttach -{ - /** - * @var string - */ - const CHAT = 'CHAT'; - /** - * @var int $id Unix timestamp - */ - protected $id; - /** - * @var string $color hex color see iAttach interface - */ - protected $color; - /** - * @var array - */ - protected $attachItems; - /** - * Attach constructor. - * @param null | int $id Unix timestamp - * @param null | string $color hex color see iAttach interface - */ - public function __construct($id = null, $color = null) - { - $this->attachItems = array(); - - if(null === $id) - { - $this->id = time(); - } - - if (self::CHAT !== $color) - { - $this->color = $color; - if(null === $this->color) - { - $this->setStatusNormal(); - } - } - } - - /** - * @param iAttachItem $attachItem - */ - public function add(iAttachItem $attachItem) - { - $this->attachItems[] = clone $attachItem; - } - - /** - * @return array - */ - public function getData() - { - return array( - 'ID' => $this->id, - 'BLOCKS' => $this->getAttachList(), - 'COLOR' => $this->color - ); - } - - /** - * @return array - */ - public function getAttachItems() - { - return $this->attachItems; - } - - /** - * @return array - */ - private function getAttachList() - { - $arResult = array(); - /** - * @var $obAttachItem iAttachItem - */ - foreach($this->getAttachItems() as $cnt => $obAttachItem) - { - $arResult[][$obAttachItem->getAttachTypeCode()] = $obAttachItem->getAttachData(); - } - return $arResult; - } - - /** - * @return mixed - */ - public function setStatusNormal() - { - $this->color = self::STATUS_NORMAL; - } - - /** - * @return mixed - */ - public function setStatusAttention() - { - $this->color = self::STATUS_ATTENTION; - } - - /** - * @return mixed - */ - public function setStatusProblem() - { - $this->color = self::STATUS_PROBLEM; - } -} \ No newline at end of file diff --git a/src/classes/im/attach/iattach.php b/src/classes/im/attach/iattach.php deleted file mode 100644 index cb730078..00000000 --- a/src/classes/im/attach/iattach.php +++ /dev/null @@ -1,49 +0,0 @@ - and contributors - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Im\Attach; -/** - * Interface iAttach - * @package Bitrix24\Im\Attach - */ -interface iAttach -{ - /** - * @var string - */ - const STATUS_NORMAL = "#aac337"; - /** - * @var string - */ - const STATUS_ATTENTION = "#e8a441"; - /** - * @var string - */ - const STATUS_PROBLEM = "#df532d"; - - /** - * @return mixed - */ - public function setStatusNormal(); - - /** - * @return mixed - */ - public function setStatusAttention(); - - /** - * @return mixed - */ - public function setStatusProblem(); - - /** - * @return array - */ - public function getAttachItems(); -} diff --git a/src/classes/im/attach/iattachitem.php b/src/classes/im/attach/iattachitem.php deleted file mode 100644 index 61b0e6e7..00000000 --- a/src/classes/im/attach/iattachitem.php +++ /dev/null @@ -1,30 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Im\Attach; -use Bitrix24\Bitrix24Entity; -use Bitrix24\Bitrix24Exception; -use Bitrix24\Presets\Im\Fields as B24ImFields; - -/** - * Interface iAttachItem - * @package Bitrix24\Im\Attach - */ -interface iAttachItem -{ - /** - * @return mixed - */ - public function getAttachData(); - - /** - * @return string - */ - public function getAttachTypeCode(); -} \ No newline at end of file diff --git a/src/classes/im/attach/item/delimiter.php b/src/classes/im/attach/item/delimiter.php deleted file mode 100644 index 5f7e5969..00000000 --- a/src/classes/im/attach/item/delimiter.php +++ /dev/null @@ -1,60 +0,0 @@ - and contributors - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Im\Attach\Item; -use Bitrix24\Im\Attach\iAttachItem; -/** - * Class Delimiter - * @package Bitrix24\Im\Attach\Item - */ -class Delimiter implements iAttachItem -{ - /** - * @var string - */ - const ATTACH_TYPE_CODE = 'DELIMITER'; - /** - * @var - */ - protected $color; - /** - * @var - */ - protected $size; - - /** - * Delimiter constructor. - * @param $size - * @param $color - */ - public function __construct($size = null, $color = null) - { - $this->size = $size; - $this->color = $color; - } - - /** - * @return array - */ - public function getAttachData() - { - return array( - 'SIZE' => $this->size, - 'COLOR' => $this->color, - ); - } - - /** - * @return string - */ - public function getAttachTypeCode() - { - return self::ATTACH_TYPE_CODE; - } -} \ No newline at end of file diff --git a/src/classes/im/attach/item/file.php b/src/classes/im/attach/item/file.php deleted file mode 100644 index 4306e86f..00000000 --- a/src/classes/im/attach/item/file.php +++ /dev/null @@ -1,67 +0,0 @@ - and contributors - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Im\Attach\Item; -use Bitrix24\Im\Attach\iAttachItem; -/** - * Class File - * @package Bitrix24\Im\Attach\Item - */ -class File implements iAttachItem -{ - /** - * @var string - */ - const ATTACH_TYPE_CODE = 'FILE'; - /** - * @var - */ - protected $name; - /** - * @var - */ - protected $link; - /** - * @var - */ - protected $size; - - /** - * Image constructor. - * @param $name - * @param $link - * @param $size - */ - public function __construct($link, $name, $size) - { - $this->name = $name; - $this->link = $link; - $this->size = $size; - } - - /** - * @return array - */ - public function getAttachData() - { - return array( - 'NAME' => $this->name, - 'LINK' => $this->link, - 'SIZE' => $this->size, - ); - } - - /** - * @return string - */ - public function getAttachTypeCode() - { - return self::ATTACH_TYPE_CODE; - } -} \ No newline at end of file diff --git a/src/classes/im/attach/item/grid.php b/src/classes/im/attach/item/grid.php deleted file mode 100644 index ea3159bc..00000000 --- a/src/classes/im/attach/item/grid.php +++ /dev/null @@ -1,114 +0,0 @@ - and contributors - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Im\Attach\Item; -use Bitrix24\Im\Attach\iAttachItem; -/** - * Class Grid - * @package Bitrix24\Im\Attach\Item - */ -class Grid implements iAttachItem -{ - /** - * @var string - */ - const ATTACH_TYPE_CODE = 'GRID'; - /** - * @var array - */ - protected $arGridItems = array(); - - /** - * Grid constructor. - */ - public function __construct() - { - } - - /** - * @param $name - * @param $value - * @param null $color - * @param null $link - * @param null $chatId - * @param null $userId - */ - public function addBlockItem($name, $value, $color = null, $link = null, $chatId = null, $userId = null) - { - $this->arGridItems[] = array( - 'DISPLAY' => 'BLOCK', - 'NAME' => $name, - 'VALUE' => $value, - 'COLOR' => $color, - 'LINK' => $link, - 'CHAT_ID' => $chatId, - 'USER_ID' => $userId - ); - } - - /** - * @param $name - * @param $value - * @param $width - * @param null $color - * @param null $link - * @param null $chatId - * @param null $userId - */ - public function addLineItem($name, $value, $width, $color = null, $link = null, $chatId = null, $userId = null) - { - $this->arGridItems[] = array( - 'DISPLAY' => 'LINE', - 'NAME' => $name, - 'VALUE' => $value, - 'WIDTH' => $width, - 'COLOR' => $color, - 'LINK' => $link, - 'CHAT_ID' => $chatId, - 'USER_ID' => $userId - ); - } - - /** - * @param $name - * @param $value - * @param null $color - * @param null $link - * @param null $chatId - * @param null $userId - */ - public function addColumnItem($name, $value, $width, $color = null, $link = null, $chatId = null, $userId = null) - { - $this->arGridItems[] = array( - 'DISPLAY' => 'COLUMN', - 'NAME' => $name, - 'VALUE' => $value, - 'WIDTH' => $width, - 'COLOR' => $color, - 'LINK' => $link, - 'CHAT_ID' => $chatId, - 'USER_ID' => $userId - ); - } - /** - * @return array - */ - public function getAttachData() - { - return $this->arGridItems; - } - - /** - * @return string - */ - public function getAttachTypeCode() - { - return self::ATTACH_TYPE_CODE; - } -} \ No newline at end of file diff --git a/src/classes/im/attach/item/image.php b/src/classes/im/attach/item/image.php deleted file mode 100644 index 6a0ce147..00000000 --- a/src/classes/im/attach/item/image.php +++ /dev/null @@ -1,60 +0,0 @@ - and contributors - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Im\Attach\Item; -use Bitrix24\Im\Attach\iAttachItem; -/** - * Class Image - * @package Bitrix24\Im\Attach\Item - */ -class Image implements iAttachItem -{ - /** - * @var string - */ - const ATTACH_TYPE_CODE = 'IMAGE'; - /** - * @var - */ - protected $name; - /** - * @var - */ - protected $link; - - /** - * Image constructor. - * @param $name - * @param $link - */ - public function __construct($name, $link) - { - $this->name = $name; - $this->link = $link; - } - - /** - * @return array - */ - public function getAttachData() - { - return array( - 'NAME' => $this->name, - 'LINK' => $this->link - ); - } - - /** - * @return string - */ - public function getAttachTypeCode() - { - return self::ATTACH_TYPE_CODE; - } -} \ No newline at end of file diff --git a/src/classes/im/attach/item/link.php b/src/classes/im/attach/item/link.php deleted file mode 100644 index 69ff3510..00000000 --- a/src/classes/im/attach/item/link.php +++ /dev/null @@ -1,75 +0,0 @@ - and contributors - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Im\Attach\Item; -use Bitrix24\Im\Attach\iAttachItem; - -/** - * Class Link - * @package Bitrix24\Im\Attach\Item - */ -class Link implements iAttachItem -{ - /** - * @var string - */ - const ATTACH_TYPE_CODE = 'LINK'; - /** - * @var - */ - protected $name; - /** - * @var - */ - protected $description; - /** - * @var - */ - protected $link; - /** - * @var string - */ - protected $preview; - - /** - * Link constructor. - * @param $name string required - * @param $link string required - * @param $description string - * @param $preview string required - */ - public function __construct($name, $link, $description, $preview) - { - $this->name = $name; - $this->link = $link; - $this->description = $description; - $this->preview = $preview; - } - - /** - * @return array - */ - public function getAttachData() - { - return array( - 'NAME' => $this->name, - 'DESC' => $this->description, - 'LINK' => $this->link, - 'PREVIEW' => $this->preview - ); - } - - /** - * @return string - */ - public function getAttachTypeCode() - { - return self::ATTACH_TYPE_CODE; - } -} \ No newline at end of file diff --git a/src/classes/im/attach/item/message.php b/src/classes/im/attach/item/message.php deleted file mode 100644 index dd3f0c38..00000000 --- a/src/classes/im/attach/item/message.php +++ /dev/null @@ -1,52 +0,0 @@ - and contributors - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Im\Attach\Item; -use Bitrix24\Im\Attach\iAttachItem; - -/** - * Class Message - * @package Bitrix24\Im\Attach\Item - */ -class Message implements iAttachItem -{ - /** - * @var string - */ - const ATTACH_TYPE_CODE = 'MESSAGE'; - /** - * @var - */ - protected $message; - - /** - * Message constructor. - * @param $message - */ - public function __construct($message) - { - $this->message = $message; - } - - /** - * @return array - */ - public function getAttachData() - { - return $this->message; - } - - /** - * @return string - */ - public function getAttachTypeCode() - { - return self::ATTACH_TYPE_CODE; - } -} \ No newline at end of file diff --git a/src/classes/im/attach/item/user.php b/src/classes/im/attach/item/user.php deleted file mode 100644 index 0872e2c9..00000000 --- a/src/classes/im/attach/item/user.php +++ /dev/null @@ -1,68 +0,0 @@ - and contributors - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Im\Attach\Item; -use Bitrix24\Im\Attach\iAttachItem; - -/** - * Class User - * @package Bitrix24\Im\Attach\Item - */ -class User implements iAttachItem -{ - /** - * @var string - */ - const ATTACH_TYPE_CODE = 'USER'; - /** - * @var - */ - protected $userName; - /** - * @var - */ - protected $avatarUrl; - /** - * @var - */ - protected $userLink; - - /** - * User constructor. - * @param $userName string required - * @param $avatarUrl string - * @param $userLink string - */ - public function __construct($userName, $avatarUrl = null, $userLink = null) - { - $this->userName = $userName; - $this->avatarUrl = $avatarUrl; - $this->userLink = $userLink; - } - - /** - * @return array - */ - public function getAttachData() - { - return array( - 'NAME' => $this->userName, - 'AVATAR' => $this->avatarUrl, - 'LINK' => $this->userLink - ); - } - - /** - * @return string - */ - public function getAttachTypeCode() - { - return self::ATTACH_TYPE_CODE; - } -} \ No newline at end of file diff --git a/src/classes/im/chat.php b/src/classes/im/chat.php deleted file mode 100644 index 07ca311d..00000000 --- a/src/classes/im/chat.php +++ /dev/null @@ -1,289 +0,0 @@ - and contributors - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Im; -use Bitrix24\Bitrix24Entity; -use Bitrix24\Bitrix24Exception; -use Bitrix24\Presets\Im\Fields as B24ImFields; -use Bitrix24\Im\Attach\Attach; - -/** - * Class Chat - * @package Bitrix24\Im - */ -class Chat extends Bitrix24Entity -{ - /** - * create new chat - * - * @param string $title - * @param string $description - * @param string $color chat color in Bitrix24\Presets\Im\iChatColor for mobile - * @param string $message - * @param array $users - * @param string $avatarImgInBase64 - * @param bool $isOpen - * - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - * - * @return array - */ - public function add($title, $description='', $color ='', $message = '', array $users = array(), $avatarImgInBase64 = null, $isOpen = false) - { - $arParams = array( - 'title' => (string) $title, - 'description' => (string) $description, - 'color' => (string) $color, - 'message' => (string) $message, - 'users' => $users, - 'avatar' => $avatarImgInBase64, - ); - - if($isOpen) - { - $arParams['type'] = 'OPEN'; - } - return $this->client->call('im.chat.add', $arParams); - } - - /** - * delete chat - * - * @param int $chatId - * - * @return array - * - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function delete($chatId) - { - return $this->client->call('im.chat.delete', array( - 'chat_id' => (int) $chatId - )); - } - - /** - * set chat owner - * - * @param $chatId - * @param $userId - * - * @return array - * - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function setOwner($chatId, $userId) - { - return $this->client->call('im.chat.setOwner', array( - 'chat_id' => (int) $chatId, - 'user_id' => (int) $userId - )); - } - - /** - * update color - * - * @param int $chatId - * @param string $newColor - * - * @return array - * - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function updateColor($chatId, $newColor) - { - return $this->client->call('im.chat.updateColor', array( - 'chat_id' => (int) $chatId, - 'color' => (string) $newColor - )); - } - - /** - * update title - * - * @param int $chatId - * @param string $newTitle - * - * @return array - * - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function updateTitle($chatId, $newTitle) - { - return $this->client->call('im.chat.updateTitle', array( - 'chat_id' => (int) $chatId, - 'title' => (string) $newTitle - )); - } - - /** - * update avatar - * - * @param int $chatId - * @param string $avatarImgInBase64 - * - * @return array - * - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function updateAvatar($chatId, $avatarImgInBase64) - { - return $this->client->call('im.chat.updateAvatar', array( - 'chat_id' => (int) $chatId, - 'avatar' => (string) $avatarImgInBase64 - )); - } - - - /** - * send typing - * - * @param int $chatId - * - * @return array - * - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function sendTyping($chatId) - { - return $this->client->call('im.chat.sendTyping', array( - 'chat_id' => (int) $chatId - )); - } - - /** - * delete user from chat - * - * @param $chatId - * @param $userId - * - * @return array - * - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function userDelete($chatId, $userId) - { - return $this->client->call('im.chat.user.delete', array( - 'chat_id' => (int) $chatId, - 'user_id' => (int) $userId - )); - } - - /** - * - * @param $chatId - * @param array $arNewUsers - * - * @return array - * - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException */ - public function userAdd($chatId, array $arNewUsers = array()) - { - return $this->client->call('im.chat.user.add', array( - 'chat_id' => (int) $chatId, - 'user_id' => $arNewUsers - )); - } - - /** - * get user list in chat - * - * @param $chatId - * - * @return array - * - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function userList($chatId) - { - return $this->client->call('im.chat.user.list', array( - 'chat_id' => (int) $chatId - )); - } -} \ No newline at end of file diff --git a/src/classes/im/im.php b/src/classes/im/im.php deleted file mode 100644 index 5be2964d..00000000 --- a/src/classes/im/im.php +++ /dev/null @@ -1,91 +0,0 @@ -client->call( - 'im.notify', - array( - 'to' => $userId, - 'message' => $message, - 'type' => strtoupper($notifyType) - ) - ); - return $fullResult; - } - - - /** - * add a message to private/public group chats - * @param int $chatId - * @param $message - * @param string $system - * @param string $userId - * @return array - */ - public function messageAdd($chatId = 1, $message, $system = 'N', $userId = '') - { - if(is_null($chatId) && empty($userId)) - { - throw new Bitrix24Exception('chat id is null and user id is empty'); - } - elseif(is_null($message)) - { - throw new Bitrix24Exception('message is null'); - } - elseif(!in_array($system, array("N", "Y"), true)) - { - throw new Bitrix24Exception('unknown system'); - } - - $arAdditionalParameters = array( - 'message' => $message, - 'system' => $system - ); - - if (!empty($userId)) { - $arAdditionalParameters['user_id'] = $userId; - } else { - $arAdditionalParameters['chat_id'] = $chatId; - } - - $fullResult = $this->client->call( - 'im.message.add', - $arAdditionalParameters - ); - return $fullResult; - } - -} \ No newline at end of file diff --git a/src/classes/im/notify.php b/src/classes/im/notify.php deleted file mode 100644 index ed70da03..00000000 --- a/src/classes/im/notify.php +++ /dev/null @@ -1,175 +0,0 @@ - and contributors - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Im; - -use Bitrix24\Bitrix24Entity; -use Bitrix24\Bitrix24Exception; -use Bitrix24\Presets\Im\Fields as B24ImFields; -use Bitrix24\Im\Attach\Attach; - -/** - * Class Notify - * @package Bitrix24\Im - */ -class Notify extends Bitrix24Entity -{ - /** - * @param $userId - * @param $message - * @param string $tag - * @param string $subTag - * @param Attach|null $attachObject - * @return array - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function addPersonal($userId, $message, $tag = '', $subTag = '', Attach $attachObject = null) - { - $arArgs = array( - 'user_id' => (int)$userId, - 'message' => (string)$message, - 'tag' => (string)$tag, - 'sub_tag' => (string)$subTag - ); - - if (null === $userId) { - throw new Bitrix24Exception('user id is null'); - } elseif (null === $message) { - throw new Bitrix24Exception('message is null'); - } elseif (null !== $attachObject) { - $arArgs['attach'] = $attachObject->getData(); - } - return $this->client->call('im.notify.personal.add', $arArgs); - } - - /** - * @param $userId - * @param $message - * @param string $tag - * @param string $subTag - * @param Attach|null $attachObject - * @return array - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function addSystem($userId, $message, $tag = '', $subTag = '', Attach $attachObject = null) - { - $arArgs = array( - 'user_id' => (int)$userId, - 'message' => (string)$message, - 'tag' => (string)$tag, - 'sub_tag' => (string)$subTag - ); - - if (null === $userId) { - throw new Bitrix24Exception('user id is null'); - } elseif (null === $message) { - throw new Bitrix24Exception('message is null'); - } elseif (null !== $attachObject) { - $arArgs['attach'] = $attachObject->getData(); - } - return $this->client->call('im.notify.system.add', $arArgs); - } - - /** - * @param $id - * @return array - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function deleteById($id) - { - if (null === $id) { - throw new Bitrix24Exception('id is null'); - } - $fullResult = $this->client->call( - 'im.notify.delete', - array( - 'id' => (int)$id - ) - ); - return $fullResult; - } - - /** - * @param $tag - * @return array - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function deleteByTag($tag) - { - if (null === $tag) { - throw new Bitrix24Exception('tag is null'); - } - $fullResult = $this->client->call( - 'im.notify.delete', - array( - 'tag' => (string)$tag - ) - ); - return $fullResult; - } - - /** - * @param $subTag - * @return array - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function deleteBySubTag($subTag) - { - if (null === $subTag) { - throw new Bitrix24Exception('subTag is null'); - } - $fullResult = $this->client->call( - 'im.notify.delete', - array( - 'sub_tag' => (string)$subTag - ) - ); - return $fullResult; - } -} \ No newline at end of file diff --git a/src/classes/log/blogpost.php b/src/classes/log/blogpost.php deleted file mode 100644 index 07e8ea8b..00000000 --- a/src/classes/log/blogpost.php +++ /dev/null @@ -1,46 +0,0 @@ -client->call('log.blogpost.get', - array( - 'ORDER' => $order, - 'FILTER'=> $filter, - )); - return $result; - } - - /** - * @param $message - * @param $title - * @param $perm - * @link https://dev.1c-bitrix.ru/rest_help/log/log_blogpost_add.php - * @throws Bitrix24Exception - * @return array - */ - public function Add($message='', $title='', $perm=array("UA")) - { - $result = $this->client->call( - 'log.blogpost.add', - array( - 'POST_MESSAGE' => $message, - 'POST_TITLE' => $title, - 'SPERM' => $perm - ) - ); - return $result; - } -} \ No newline at end of file diff --git a/src/classes/placement/Placement.php b/src/classes/placement/Placement.php deleted file mode 100644 index 3673818a..00000000 --- a/src/classes/placement/Placement.php +++ /dev/null @@ -1,74 +0,0 @@ -client->call('placement.bind', - array( - 'PLACEMENT' => $placementCode, - 'HANDLER' => $handlerUrl, - 'TITLE' => $title, - 'DESCRIPTION' => $description - )); - return $arResult; - } - - /** - * unregister placement handler - * - * @param $placementCode string - * @param $handlerUrl string - * - * @return array - */ - public function unbind($placementCode, $handlerUrl) - { - $arResult = $this->client->call('placement.unbind', - array( - 'PLACEMENT' => $placementCode, - 'HANDLER' => $handlerUrl - )); - return $arResult; - } - - /** - * Get possible placement locations - * - * @return array - */ - public function getPossibleLocations() - { - $arResult = $this->client->call('placement.list'); - return $arResult['result']; - } - - /** - * get locations with registered placements - * - * @return array - */ - public function getLocations() - { - $arResult = $this->client->call('placement.get'); - return $arResult['result']; - } -} \ No newline at end of file diff --git a/src/classes/sonet/sonetgroup.php b/src/classes/sonet/sonetgroup.php deleted file mode 100644 index c857cf12..00000000 --- a/src/classes/sonet/sonetgroup.php +++ /dev/null @@ -1,179 +0,0 @@ -client->call('sonet_group.get', - array( - 'ORDER' => $order, - 'FILTER'=> $filter, - )); - return $result; - } - - /** - * @param $name - * @param $initiate_perms - * @param $arFields - * @link https://dev.1c-bitrix.ru/rest_help/socialnetwork/sonet_group/sonet_group_create.php - * @throws Bitrix24Exception - * @return array - */ - public function Create($name, $initiate_perms, $arFields) - { - $result = $this->client->call('sonet_group.create', - array_merge( - array( - 'NAME' => $name, - 'INITIATE_PERMS' => $initiate_perms - ), - $arFields - )); - return $result; - } - - /** - * @param $group_id - * @param $arFields - * @link https://dev.1c-bitrix.ru/api_help/socialnetwork/classes/CSocNetGroup/Update.php - * @throws Bitrix24Exception - * @return array - */ - public function Update($group_id, $arFields) - { - $result = $this->client->call('sonet_group.update', - array_merge( - array('GROUP_ID' => $group_id), - $arFields - )); - return $result; - } - - /** - * @param $group_id - * @link https://dev.1c-bitrix.ru/rest_help/socialnetwork/sonet_group/sonet_group_delete.php - * @throws Bitrix24Exception - * @return array - */ - public function Delete($group_id) - { - $result = $this->client->call('sonet_group.delete', - array( - 'GROUP_ID' => $group_id - )); - return $result; - } - - /** - * @param $group_id - * @param $user_id - * @link https://dev.1c-bitrix.ru/rest_help/socialnetwork/sonet_group/sonet_group_setowner.php - * @throws Bitrix24Exception - * @return array - */ - public function SetOwner($group_id, $user_id) - { - $result = $this->client->call('sonet_group.setowner', - array( - 'GROUP_ID' => $group_id, - 'USER_ID'=> $user_id - )); - return $result; - } - - /** - * @param $id - * @link https://dev.1c-bitrix.ru/rest_help/socialnetwork/sonet_group/sonet_group_user_get.php - * @throws Bitrix24Exception - * @return array - */ - public function UserGet($id) - { - $result = $this->client->call('sonet_group.user.get', - array( - 'ID' => $id - ) - ); - return $result; - } - - /** - * @param $group_id - * @param $user_id - * @param $message - * @link https://dev.1c-bitrix.ru/rest_help/socialnetwork/sonet_group/sonet_group_user_invite.php - * @throws Bitrix24Exception - * @return array - */ - public function Invate($group_id, $user_id, $message) - { - $result = $this->client->call('sonet_group.user.invite', - array( - 'GROUP_ID' => $group_id, - 'USER_ID'=> $user_id, - 'MESSAGE'=> $message - ) - ); - return $result; - } - - /** - * @param $group_id - * @param $message - * @link https://dev.1c-bitrix.ru/rest_help/socialnetwork/sonet_group/sonet_group_user_request.php - * @throws Bitrix24Exception - * @return array - */ - public function Request($group_id, $message) - { - $result = $this->client->call('sonet_group.user.request', - array( - 'GROUP_ID' => $group_id, - 'MESSAGE'=> $message - ) - ); - return $result; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/socialnetwork/sonet_group/sonet_group_user_groups.php - * @throws Bitrix24Exception - * @return array - */ - public function UserGroups() - { - $result= $this->client->call('sonet_group.user.groups'); - return $result; - } - - /** - * @param $group_id - * @param $feature - * @param $operation - * @link https://dev.1c-bitrix.ru/rest_help/socialnetwork/sonet_group/sonet_group_feature_access.php - * @throws Bitrix24Exception - * @return array - */ - public function FeatureAccess($group_id, $feature, $operation) - { - $result = $this->client->call('sonet_group.feature.access', - array( - 'GROUP_ID' => $group_id, - 'FEATURE' => $feature, - 'OPERATION' => $operation - )); - return $result; - } -} \ No newline at end of file diff --git a/src/classes/task/checklistitem.php b/src/classes/task/checklistitem.php deleted file mode 100644 index 7c6cfd4e..00000000 --- a/src/classes/task/checklistitem.php +++ /dev/null @@ -1,169 +0,0 @@ -client->call('task.checklistitem.getmanifest'); - return $result; - } - - /** - * Returns the list of check list elements in a task. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/getlist.php - * @param $taskId integer Task identifier. Required parameter. - * @param $order array Array for result sorting. The sorting field can take the following values: - * ID � check list element identifier; - * CREATED_BY � identifier of the user who has created the element; - * TOGGLED_BY � identifier of the user who has modified the check list element status; - * TOGGLED_DATE � the time when the check list element status was changed; - * TITLE � check list element header; - * SORT_INDEX � element sorting index; - * IS_COMPLETE � the element is marked as completed; - * The sorting direction can take the following values: - * asc � ascending; - * desc � descending; - * Optional. By default it is filtered by descending identifier of a check list element. - * @return array - */ - public function getList($taskId, $order) - { - $result = $this->client->call('task.checklistitem.getlist', - array( - 'TASKID' => $taskId, - 'ORDER' => $order - )); - return $result; - } - - /** - * Returns a check list element by its identifier. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/get.php - * @param $taskId integer Task identifier. Required parameter. - * @param $checklistItemId integer Element identifier. Required parameter. - * @return array - */ - public function get($taskId, $checklistItemId) - { - $result = $this->client->call('task.checklistitem.get', - array( - 'TASKID' => $taskId, - 'ITEMID' => $checklistItemId - )); - return $result; - } - - /** - * Adds a new check list element to a task. Returns the identifier of the added element. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/add.php - * @param $taskId integer Task identifier. Required parameter. - * @param $fields array Array of fields of a check list element (TITLE, SORT_INDEX, IS_COMPLETE). Required parameter. - * @return array - */ - public function add($taskId, $fields) - { - $result = $this->client->call('task.checklistitem.add', array($taskId, $fields)); - return $result; - } - - /** - * Updates data of a check list element. - * Before updating data, it is advisable to make sure the action is permitted (task.checklistitem.isactionallowed). - * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/update.php - * @param $taskId integer Task identifier. Required parameter. - * @param $checklistItemId integer Check list element identifier. Required parameter. - * @param $fields array Array of fields of a check list elements (TITLE, SORT_INDEX, IS_COMPLETE). Required parameter. - * @return array - */ - public function update($taskId, $checklistItemId, $fields) - { - $result = $this->client->call('task.checklistitem.update', array($taskId, $checklistItemId, array($fields))); - return $result; - } - - /** - * Deletes check list element. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/complete.php - * @param $taskId integer Task identifier. Required parameter. - * @param $checklistItemId integer Check list element identifier. Required parameter. - * @return array - */ - public function delete($taskId, $checklistItemId) - { - $result = $this->client->call('task.checklistitem.delete', array($taskId, $checklistItemId)); - return $result; - } - - /** - * Marks a check list element as completed. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/complete.php - * @param $taskId integer Task identifier. Required parameter. - * @param $checklistItemId integer Check list element identifier. Required parameter. - * @return array - */ - public function complete($taskId, $checklistItemId) - { - $result = $this->client->call('task.checklistitem.complete', array($taskId, $checklistItemId)); - return $result; - } - - /** - * Marks a check list element as active again. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/renew.php - * @param $taskId integer Task identifier. Required parameter. - * @param $checklistItemId integer Check list element identifier. Required parameter. - * @return array - */ - public function renew($taskId, $checklistItemId) - { - $result = $this->client->call('task.checklistitem.renew', array($taskId, $checklistItemId)); - return $result; - } - - /** - * Moves a check list element and places it in the list after the indicated one. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/moveafteritem.php - * @param $taskId integer Task identifier. Required parameter. - * @param $checklistItemId integer Check list element identifier. Required parameter. - * @param $checklistAfterItemId integer Check list element identifier, after which the given element will be placed. Required parameter. - * @return array - */ - public function moveAfterItem($taskId, $checklistItemId, $checklistAfterItemId) - { - $result = $this->client->call('task.checklistitem.moveafteritem', array($taskId, $checklistItemId, $checklistAfterItemId)); - return $result; - } - - /** - * Checks whether the action is permitted. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/isactionallowed.php - * @param $taskId integer Task identifier. Required parameter. - * @param $checklistItemId integer Comment identifier. Required parameter. - * @param $actionId integer Identifier of the action to be checked: - * 1 - ACTION_ADD; - * 2 - ACTION_MODIFY; - * 3 - ACTION_REMOVE; - * 4 - ACTION_TOGGLE. - * Required parameter. - * @return array - */ - public function isActionAllowed($taskId, $checklistItemId, $actionId) - { - $result = $this->client->call('task.checklistitem.isactionallowed', array($taskId, $checklistItemId, $actionId)); - return $result; - } -} diff --git a/src/classes/task/commentitem.php b/src/classes/task/commentitem.php deleted file mode 100644 index 03867961..00000000 --- a/src/classes/task/commentitem.php +++ /dev/null @@ -1,115 +0,0 @@ -client->call('task.commentitem.getmanifest'); - return $result; - } - - /** - * Returns the list of comments to a task. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/commentitem/getlist.php - * @param $taskId integer - * @param $order array - * @param $filter array - * @return array - */ - public function getList($taskId, $order, $filter) - { - $result = $this->client->call('task.commentitem.getlist', array($taskId, $order, $filter)); - return $result; - } - - /** - * Returns comments to a task. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/commentitem/get.php - * @param $taskId integer Task identifier. Required parameter. - * @param $commentItemId integer Comment identifier. Required parameter. - * @return array - */ - public function get($taskId, $commentItemId) - { - $result = $this->client->call('task.commentitem.get', - array( - 'TASKID' => $taskId, - 'ITEMID' => $commentItemId - )); - return $result; - } - - /** - * Creates a new comment to a task. Returns the identifier to the comment added. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/commentitem/add.php - * @param $taskId integer Task identifier. Required parameter. - * @param $fields array Data field array for a task (POST_MESSAGE). Required parameter. - * @return array - */ - public function add($taskId, $fields) - { - $result = $this->client->call('task.commentitem.add', - array( - 'TASKID' => $taskId, - 'arFields' => $fields - )); - return $result; - } - - /** - * Updates the comment data. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/commentitem/update.php - * @param $taskId integer Task identifier. Required parameter. - * @param $commentItemId integer Comment identifier. Required parameter. - * @param $fields array Data field array for a task (POST_MESSAGE). Required parameter. - * @return array - */ - public function update($taskId, $commentItemId, $fields) - { - $result = $this->client->call('task.commentitem.add', array($taskId, $commentItemId, array($fields))); - return $result; - } - - /** - * Delete a comment. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/commentitem/delete.php - * @param $taskId integer Task identifier. Required parameter. - * @param $commentItemId integer Comment identifier. Required parameter. - * @return array - */ - public function delete($taskId, $commentItemId) - { - $result = $this->client->call('task.commentitem.add', array($taskId, $commentItemId)); - return $result; - } - - /** - * Checks if the action is permitted. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/isactionallowed.php - * @param $taskId integer Task identifier. Required parameter. - * @param $commentItemId integer Comment identifier. Required parameter. - * @param $actionId integer Identifier of the action to be checked: - * 1 - ACTION_COMMENT_ADD; - * 2 - ACTION_COMMENT_MODIFY; - * 3 - ACTION_COMMENT_REMOVE. - Required parameter. - * @return array - */ - public function isActionAllowed($taskId, $commentItemId, $actionId) - { - $result = $this->client->call('task.commentitem.isactionallowed', array($taskId, $commentItemId, $actionId)); - return $result; - } -} diff --git a/src/classes/task/elapseditem.php b/src/classes/task/elapseditem.php deleted file mode 100644 index 9d237ff9..00000000 --- a/src/classes/task/elapseditem.php +++ /dev/null @@ -1,141 +0,0 @@ -client->call('task.elapseditem.getmanifest'); - return $result; - } - - /** - * Returns a list of entries about elapsed time for a task. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/getlist.php - * @param $taskId integer Task identifier. Required parameter. - * @param $order array Array for result sorting. Sorting field may take the following values: - * ID � identifier of the entry about elapsed time; - * USER_ID � identifier of the user on whose behalf the entry about the elapsed time was made; - * MINUTES � elapsed time, minutes; - * SECONDS � elapsed time, seconds ; - * CREATED_DATE � entry creation date; - * DATE_START � start date; - * DATE_STOP � end date. - * Sorting direction can take the following values: - * asc � ascending; - * desc � descending; - * Optional. By default it is filtered by descending of the entry elapsed time identifier. - * @param $filter array Array of the time {"filtered_field": "filter value" [, ...]}. Filtered field can take the following values: - * ID � comment identifier; - * USER_ID � identifier of the user on whose behalf the entry about the elapsed time was made; - * CREATED_DATE � entry creation date. - * Filtration type may be indicated before the name of the field to be filtered: - * "!" � not equal; - * "<" � less; - * "<=" � less or equal; - * ">" � more; - * ">=" � more or equal. - * filter values - a single value or an array. - * Optional. By default entries are not filtered. - * @return array - */ - public function getList($taskId, $order, $filter) - { - $result = $this->client->call('task.elapseditem.getlist', - array( - 'TASKID' => $taskId, - 'ORDER' => $order, - 'FILTER' => $filter - )); - return $result; - } - - /** - * Returns an entry about elapsed time by its identifier. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/elapseditem/get.php - * @param $taskId integer Task identifier. Required parameter. - * @param $elapsedItemId integer Entry identifier. Required parameter. - * @return array - */ - public function get($taskId, $elapsedItemId) - { - $result = $this->client->call('task.checklistitem.get', - array( - 'TASKID' => $taskId, - 'ITEMID' => $elapsedItemId - )); - return $result; - } - - /** - * Add time spent to the task. Return added record ID. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/elapseditem/add.php - * @param $taskId integer Task identifier. Required parameter. - * @param $fields array Array of time records and comments (SECONDS and COMMENT_TEXT). MINUTES may be used instead of SECONDS, but they may not be used at the same time. - * @return array - */ - public function add($taskId, $fields) - { - $result = $this->client->call('task.elapseditem.add', array($taskId, $fields)); - return $result; - } - - /** - * Change parameters of the specified time spent record. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/elapseditem/update.php - * @param $taskId integer Task identifier. Required parameter. - * @param $elapsedItemId integer Entry identifier. Required parameter. - * @param $fields array Array of time records and comments (SECONDS and COMMENT_TEXT). MINUTES may be used instead of SECONDS, but they may not be used at the same time. - * @return array - */ - public function update($taskId, $elapsedItemId, $fields) - { - $result = $this->client->call('task.elapseditem.update', array($taskId, $elapsedItemId, array($fields))); - return $result; - } - - /** - * Delete time spent record. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/elapseditem/delete.php - * @param $taskId integer Task identifier. Required parameter. - * @param $elapsedItemId integer Time spent record ID. - * @return array - */ - public function delete($taskId, $elapsedItemId) - { - $result = $this->client->call('task.elapseditem.delete', array($taskId, $elapsedItemId)); - return $result; - } - - /** - * Verify whether the action is allowed. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/elapseditem/isactionallowed.php - * @param $taskId integer Task identifier. Required parameter. - * @param $elapsedItemId integer Time spent record ID. - * @param $actionId integer Identifier of the action to be checked: - * Action ID: - * 1 - ACTION_ELAPSED_TIME_ADD; - * 2 - ACTION_ELAPSED_TIME_MODIFY; - * 3 - ACTION_ELAPSED_TIME_REMOVE. - * Required parameter. - * @return array - */ - public function isActionAllowed($taskId, $elapsedItemId, $actionId) - { - $result = $this->client->call('task.elapseditem.isActionAllowed', array($taskId, $elapsedItemId, $actionId)); - return $result; - } -} \ No newline at end of file diff --git a/src/classes/task/item.php b/src/classes/task/item.php deleted file mode 100644 index 9b7a2e6b..00000000 --- a/src/classes/task/item.php +++ /dev/null @@ -1,237 +0,0 @@ -client->call('task.item.getmanifest'); - return $result; - } - - /** - * add new task - * @link http://dev.1c-bitrix.ru/rest_help/tasks/task/item/add.php - * @link http://dev.1c-bitrix.ru/rest_help/tasks/fields.php - * @param array $taskData - * @return array new task ID - * @throws Bitrix24Exception - */ - public function add($taskData) - { - $result = $this->client->call('task.item.add', array($taskData)); - return $result; - } - - /** - * Return array of task data fields (TITLE, DESCRIPTION, etc.) - * @param $taskId - * @return array - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function getData($taskId) - { - $result = $this->client->call('task.item.getdata', array($taskId)); - return $result; - } - - /** - * Update task data. The following fields may be updated. Business logic and permissions are taken into account when updating task data. - * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/update.php - * @param $taskId integer Task ID. - * @param $taskData array List of updated fields. - * @return array - * - */ - public function update($taskId, $taskData) - { - $result = $this->client->call('task.item.update', array($taskId, $taskData)); - return $result; - } - - /** - * Delete task. - * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/delete.php - * @param $taskId integer Task ID. - * @return array - */ - public function delete($taskId) - { - $result = $this->client->call('task.item.delete', array($taskId)); - return $result; - } - - /** - * Return task description. - * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/getdescription.php - * @param $taskId integer Task ID. - * @param $format integer 1 (Corresponds to the PHP constant CTaskItem::DESCR_FORMAT_RAW) � - * description will be returned in the format it is stored in the database (HTML or BB-code), will not be sanitized; - * 2 (Corresponds to the PHP constant CTaskItem::DESCR_FORMAT_HTML) � description will be returned in HTML, will first be sanitized (if included in task module settings); - * 3 (Corresponds to the PHP constant CTaskItem::DESCR_FORMAT_PLAIN_TEXT) � description will be returned as plain text (no HTML tags). - * @return array - */ - public function getDescription($taskId, $format) - { - $result = $this->client->call('task.item.getdescription', $taskId, $format); - return $result; - } - - /** - * Return array of links to files attached to the task. - * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/getfiles.php - * @param $taskId integer Task ID. - * @return array - */ - public function getFiles($taskId) - { - $result = $this->client->call('task.item.getfiles', array($taskId)); - return $result; - } - - /** - * Return array with parent task IDs - * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/getdependson.php - * @param $taskId integer Task ID. - * @return array - */ - public function getDependSon($taskId) - { - $result = $this->client->call('task.item.getdependson', array($taskId)); - return $result; - } - - /** - * Return array of allowed task actions IDs (see PHP class constants CTaskItem). - * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/getallowedactions.php - * @param $taskId integer Task ID. - * @return array - */ - public function getAllowedActions($taskId) - { - $result = $this->client->call('task.item.getallowedactions', array($taskId)); - return $result; - } - - /** - * Return an array whose keys are acton names (the names correspond to PHP class constants CTaskItem) and values show whether the action is allowed (true) or not allowed (false). - * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/getallowedtaskactionsasstrings.php - * @param $taskId integer Task ID. - * @return array - */ - public function getAllowedTaskActionsAsStrings($taskId) - { - $result = $this->client->call('task.item.getallowedtaskactionsasstrings', array($taskId)); - return $result; - } - - /** - * Return true if action is allowed, else returns false. - * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/isactionallowed.php - * @param $taskId integer Task ID. - * @param $actionId integer Validated action ID (see CTaskItem::ACTION_* constants of PHP class CTaskItem). - * @return array - */ - public function isActionAllowed($taskId, $actionId) - { - $result = $this->client->call('task.item.isactionallowed', array($taskId), array($actionId)); - return $result; - } - - /** - * Delegate task to a user. - * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/delegate.php - * @param $taskId integer Task ID - * @param $userId integer New responsible person ID - * @return array - */ - public function delegate($taskId, $userId) - { - $result = $this->client->call('task.item.delegate', array($taskId), array($userId)); - return $result; - } - - /** - * Change task status to In Progress - * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/startexecution.php - * @param $taskId integer Task ID - * @return array - */ - public function startExecution($taskId) - { - $result = $this->client->call('task.item.startexecution', array($taskId)); - return $result; - } - - /** - * Change task status to Deferred - * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/defer.php - * @param $taskId integer Task ID - * @return array - */ - public function defer($taskId) - { - $result = $this->client->call('task.item.defer', array($taskId)); - return $result; - } - - /** - * Change status to Completed or Supposedly completed (requires creator's attention). - * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/complete.php - * @param $taskId integer Task ID - * @return array - */ - public function complete($taskId) - { - $result = $this->client->call('task.item.complete', array($taskId)); - return $result; - } - - /** - * Change status to Pending. - * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/renew.php - * @param $taskId integer Task ID - * @return array - */ - public function renew($taskId) - { - $result = $this->client->call('task.item.renew', array($taskId)); - return $result; - } - - /** - * Change status of task waiting for confirmation to Completed. - * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/approve.php - * @param $taskId integer Task ID - * @return array - */ - public function approve($taskId) - { - $result = $this->client->call('task.item.approve', array($taskId)); - return $result; - } - - /** - * Change status of task waiting for confirmation to Pending. - * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/disapprove.php - * @param $taskId integer Task ID - * @return array - */ - public function disapprove($taskId) - { - $result = $this->client->call('task.item.disapprove', array($taskId)); - return $result; - } -} \ No newline at end of file diff --git a/src/classes/task/items.php b/src/classes/task/items.php deleted file mode 100644 index fe057ccc..00000000 --- a/src/classes/task/items.php +++ /dev/null @@ -1,34 +0,0 @@ -client->call( - 'task.items.getlist', - array( - 'ORDER' => $ORDER, - 'FILTER'=> $FILTER, - 'TASKDATA'=> $TASKDATA, - array('NAV_PARAMS'=> $NAV_PARAMS) - ) - ); - return $fullResult; - } -} \ No newline at end of file diff --git a/src/classes/task/planner.php b/src/classes/task/planner.php deleted file mode 100644 index 0f42610a..00000000 --- a/src/classes/task/planner.php +++ /dev/null @@ -1,20 +0,0 @@ -client->call('task.planner.getlist'); - return $fullResult; - } -} \ No newline at end of file diff --git a/src/classes/user/user.php b/src/classes/user/user.php deleted file mode 100644 index 83ed2d8e..00000000 --- a/src/classes/user/user.php +++ /dev/null @@ -1,83 +0,0 @@ -client->call('user.admin'); - return $result['result']; - } - - /** - * Get information about current user by his auth information. This method will be use security sign automatically - * @link http://dev.1c-bitrix.ru/rest_help/users/user_current.php - * @throws Bitrix24Exception - * @return array - */ - public function current() - { - $result = $this->client->call('user.current', array('state' => $this->client->getSecuritySignSalt())); - return $result; - } - - /** - * Get list of fields entity user - * @link http://dev.1c-bitrix.ru/rest_help/users/user_fields.php - * @throws Bitrix24Exception - * @return array - */ - public function fields() - { - $result = $this->client->call('user.fields'); - return $result; - } - - /** - * Get list of users - * @link http://dev.1c-bitrix.ru/rest_help/users/user_get.php - * @throws Bitrix24Exception - * @param $SORT - field name to sort by them - * @param $ORDER - sort direction? must be set to ASC or DESC - * @param $FILTER - list of fields user entity to filter result - * @return array - */ - public function get($SORT, $ORDER, $FILTER, $OFFSET = 0) - { - $result = $this->client->call('user.get', - array( - 'SORT' => $SORT, - 'ORDER' => $ORDER, - 'FILTER'=> $FILTER, - 'start' => $OFFSET) - ); - return $result; - } - - - /** - * Check if current user has any of access rights specified by $access param - * @link http://dev.1c-bitrix.ru/rest_help/general/user_access.php - * @throws Bitrix24Exception - * @param array $access - list of access rights to check - * @return array - */ - public function access($access) - { - $result = $this->client->call('user.access', - array( - 'ACCESS' => $access - ) - ); - return $result; - } -} - diff --git a/src/classes/userfieldtype/UserfieldType.php b/src/classes/userfieldtype/UserfieldType.php deleted file mode 100644 index b5362bc2..00000000 --- a/src/classes/userfieldtype/UserfieldType.php +++ /dev/null @@ -1,126 +0,0 @@ -client->call('userfieldtype.add', array( - 'USER_TYPE_ID' => $userTypeId, - 'HANDLER' => $handlerUrl, - 'TITLE' => $title, - 'DESCRIPTION' => $description, - )); - } - - /** - * update userfield type - * - * @param $userTypeId - * @param $handlerUrl - * @param $title - * @param $description - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - */ - public function update($userTypeId, $handlerUrl, $title, $description) - { - return $this->client->call('userfieldtype.update', array( - 'USER_TYPE_ID' => $userTypeId, - 'HANDLER' => $handlerUrl, - 'TITLE' => $title, - 'DESCRIPTION' => $description, - )); - } - - /** - * delete userfield type - * - * @param $userTypeId - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - */ - public function delete($userTypeId) - { - return $this->client->call('userfieldtype.delete', array( - 'USER_TYPE_ID' => $userTypeId, - )); - } - - /** - * get list of userfield type - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - */ - public function getList() - { - return $this->client->call('userfieldtype.list'); - } -} \ No newline at end of file diff --git a/src/contracts/ibitrix24.php b/src/contracts/ibitrix24.php deleted file mode 100644 index c328223f..00000000 --- a/src/contracts/ibitrix24.php +++ /dev/null @@ -1,364 +0,0 @@ - value1, CURLOPT_XXX2 => value2,...) - * @return bool - */ - public function setCustomCurlOptions($options); - - /** - * Return raw request, contain all cURL options array and API query. Data available after you try to call method call - * numbers of array keys is const of cURL module. Example: CURLOPT_RETURNTRANSFER = 19913 - * @return array | null - */ - public function getRawRequest(); - - /** - * Return result from function curl_getinfo. Data available after you try to call method call - * @return array | null - */ - public function getRequestInfo(); - - /** - * Return additional parameters of last api-call. Data available after you try to call method call - * @return array | null - */ - public function getMethodParameters(); - - /** - * Execute Bitrix24 REST API method - * - * @param string $methodName - * @param array $additionalParameters - * - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24TokenIsInvalidException - * @throws Bitrix24TokenIsExpiredException - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24PaymentRequiredException - * @throws Bitrix24SecurityException - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24PortalRenamedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * - * @return array - */ - public function call($methodName, array $additionalParameters = array()); - - /** - * Get raw response from Bitrix24 before json_decode call, method available only in debug mode. - * To activate debug mode you must before set to true flag isSaveRawResponse in class construct - * @throws Bitrix24Exception - * @return string - */ - public function getRawResponse(); - - /** - * Get new access token - * - * @return array - * - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24PortalRenamedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * @throws Bitrix24TokenIsInvalidException - * @throws Bitrix24TokenIsExpiredException - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24PaymentRequiredException - * - */ - public function getNewAccessToken(); - - /** - * Authorize and get first access token - * - * @param $code - * - * @return array - * - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24PortalRenamedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * @throws Bitrix24TokenIsInvalidException - * @throws Bitrix24TokenIsExpiredException - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24PaymentRequiredException - * - */ - public function getFirstAccessToken($code); - - /** - * Check is access token expire, call list of all available api-methods from B24 portal with current access token - * if we have an error code expired_token then return true else return false - * - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24PortalRenamedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * @throws Bitrix24TokenIsInvalidException - * @throws Bitrix24TokenIsExpiredException - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24PaymentRequiredException - * - * @return boolean - */ - public function isAccessTokenExpire(); - - /** - * Get list of all methods available for current application - * @param array | null $applicationScope - * @param bool $isFull - * @return array - * @throws Bitrix24Exception - */ - public function getAvailableMethods(array $applicationScope = array(), $isFull = false); - - /** - * get list of scope for current application from bitrix24 api - * @param bool $isFull - * @throws Bitrix24Exception - * @return array - */ - public function getScope($isFull = false); - - /** - * set CURL request count retries - * @param $retriesCnt - * @return boolean - */ - public function setRetriesToConnectCount($retriesCnt = 1); - - /** - * set retries to connect timeout in microseconds - * @param $microseconds - * @return boolean - */ - public function setRetriesToConnectTimeout($microseconds = 1000000); - - /** - * get CURL request count retries - * @return int - */ - public function getRetriesToConnectCount(); - - /** - * get retries to connect timeout in microseconds - * @return mixed - */ - public function getRetriesToConnectTimeout(); - - /** - * Add call to batch. If [[$callback]] parameter is set, it will receive call result as first parameter. - * - * @param string $method - * @param array $parameters - * @param callable|null $callback - * - * @return string Unique call ID. - */ - public function addBatchCall($method, array $parameters = array(), callable $callback = null); - - /** - * Process batch calls. - * - * @param int $halt Halt batch on error - * @param int $delay Delay between batch calls (in msec) - * - * @throws Bitrix24Exception - * @throws Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - */ - public function processBatchCalls($halt = 0, $delay = self::BATCH_DELAY); - - /** - * Return true, if we have unprocessed batch calls. - * - * @return bool - */ - public function hasBatchCalls(); -} \ No newline at end of file diff --git a/src/exceptions/bitrix24apiexception.php b/src/exceptions/bitrix24apiexception.php deleted file mode 100644 index 04c2b405..00000000 --- a/src/exceptions/bitrix24apiexception.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Exceptions; - -/** - * Class Bitrix24PaymentRequiredException - * @package Bitrix24 - */ -class Bitrix24ApiException extends Bitrix24Exception -{ -} \ No newline at end of file diff --git a/src/exceptions/bitrix24badgatewayexception.php b/src/exceptions/bitrix24badgatewayexception.php deleted file mode 100644 index 7094504f..00000000 --- a/src/exceptions/bitrix24badgatewayexception.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Exceptions; - -/** - * Class Bitrix24BadGatewayException - * @package Bitrix24 - */ -class Bitrix24BadGatewayException extends Bitrix24IoException -{ -} \ No newline at end of file diff --git a/src/exceptions/bitrix24emptyresponseexception.php b/src/exceptions/bitrix24emptyresponseexception.php deleted file mode 100644 index 1342d227..00000000 --- a/src/exceptions/bitrix24emptyresponseexception.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Exceptions; - -/** - * Class Bitrix24IOException - * @package Bitrix24 - */ -class Bitrix24EmptyResponseException extends Bitrix24IoException -{ -} \ No newline at end of file diff --git a/src/exceptions/bitrix24exception.php b/src/exceptions/bitrix24exception.php deleted file mode 100644 index 68f6f75a..00000000 --- a/src/exceptions/bitrix24exception.php +++ /dev/null @@ -1,33 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Exceptions; - -/** - * Class Bitrix24Exception - * - * \Exception - * \Bitrix24Exception — base class - * \Bitrix24IoException — I/O network errors - * \Bitrix24EmptyResponseException — empty response from Bitrix24 portal - * \Bitrix24ApiException — API level errors - * \Bitrix24WrongClientException — Wrong client or application will be deleted from portal - * \Bitrix24MethodNotFoundException — API-method not found - * \Bitrix24TokenIsInvalidException — The access token provided is invalid - * \Bitrix24TokenIsExpiredException — The access token provided has expired - * \Bitrix24PortalDeletedException — Bitrix24 portal deleted - * \Bitrix24PortalRenamedException — Bitrix24 portal renamed - * \Bitrix24PaymentRequiredException — Bitrix24 application payment required - * \Bitrix24SecurityException — Security errors for protected methods - * - * @package Bitrix24\Exceptions - */ -class Bitrix24Exception extends \Exception -{ -} \ No newline at end of file diff --git a/src/exceptions/bitrix24insufficientscope.php b/src/exceptions/bitrix24insufficientscope.php deleted file mode 100644 index 74084906..00000000 --- a/src/exceptions/bitrix24insufficientscope.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Exceptions; - -/** - * Class Bitrix24InsufficientScope - * @package Bitrix24 - */ -class Bitrix24InsufficientScope extends Bitrix24ApiException -{ -} \ No newline at end of file diff --git a/src/exceptions/bitrix24ioexception.php b/src/exceptions/bitrix24ioexception.php deleted file mode 100644 index 5817969b..00000000 --- a/src/exceptions/bitrix24ioexception.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Exceptions; - -/** - * Class Bitrix24IoException - * @package Bitrix24 - */ -class Bitrix24IoException extends Bitrix24Exception -{ -} \ No newline at end of file diff --git a/src/exceptions/bitrix24methodnotfoundexception.php b/src/exceptions/bitrix24methodnotfoundexception.php deleted file mode 100644 index 78116a25..00000000 --- a/src/exceptions/bitrix24methodnotfoundexception.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Exceptions; - -/** - * Class Bitrix24WrongClientException - * @package Bitrix24 - */ -class Bitrix24MethodNotFoundException extends Bitrix24ApiException -{ -} \ No newline at end of file diff --git a/src/exceptions/bitrix24paymentrequiredexception.php b/src/exceptions/bitrix24paymentrequiredexception.php deleted file mode 100644 index dce1d1a0..00000000 --- a/src/exceptions/bitrix24paymentrequiredexception.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Exceptions; - -/** - * Class Bitrix24PaymentRequiredException - * @package Bitrix24 - */ -class Bitrix24PaymentRequiredException extends Bitrix24ApiException -{ -} \ No newline at end of file diff --git a/src/exceptions/bitrix24portaldeletedexception.php b/src/exceptions/bitrix24portaldeletedexception.php deleted file mode 100644 index 9001a5cc..00000000 --- a/src/exceptions/bitrix24portaldeletedexception.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Exceptions; - -/** - * Class Bitrix24PortalDeletedException - * @package Bitrix24 - */ -class Bitrix24PortalDeletedException extends Bitrix24ApiException -{ -} \ No newline at end of file diff --git a/src/exceptions/bitrix24portalrenamedexception.php b/src/exceptions/bitrix24portalrenamedexception.php deleted file mode 100644 index 6656f52d..00000000 --- a/src/exceptions/bitrix24portalrenamedexception.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Exceptions; - -/** - * Class Bitrix24PortalRenamedException - * @package Bitrix24 - */ -class Bitrix24PortalRenamedException extends Bitrix24ApiException -{ -} \ No newline at end of file diff --git a/src/exceptions/bitrix24securityexception.php b/src/exceptions/bitrix24securityexception.php deleted file mode 100644 index aeda62ce..00000000 --- a/src/exceptions/bitrix24securityexception.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Exceptions; - -/** - * Class Bitrix24SecurityException - * @package Bitrix24 - */ -class Bitrix24SecurityException extends Bitrix24Exception -{ -} \ No newline at end of file diff --git a/src/exceptions/bitrix24tokenisexpiredexception.php b/src/exceptions/bitrix24tokenisexpiredexception.php deleted file mode 100644 index 9c6fa130..00000000 --- a/src/exceptions/bitrix24tokenisexpiredexception.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Exceptions; - -/** - * Class Bitrix24TokenIsExpiredException - * @package Bitrix24 - */ -class Bitrix24TokenIsExpiredException extends Bitrix24ApiException -{ -} \ No newline at end of file diff --git a/src/exceptions/bitrix24tokenisinvalidexception.php b/src/exceptions/bitrix24tokenisinvalidexception.php deleted file mode 100644 index 28c18571..00000000 --- a/src/exceptions/bitrix24tokenisinvalidexception.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Exceptions; - -/** - * Class Bitrix24TokenIsInvalidException - * @package Bitrix24 - */ -class Bitrix24TokenIsInvalidException extends Bitrix24ApiException -{ -} \ No newline at end of file diff --git a/src/exceptions/bitrix24wrongclientexception.php b/src/exceptions/bitrix24wrongclientexception.php deleted file mode 100644 index 92c280a9..00000000 --- a/src/exceptions/bitrix24wrongclientexception.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Exceptions; - -/** - * Class Bitrix24WrongClientException - * @package Bitrix24 - */ -class Bitrix24WrongClientException extends Bitrix24ApiException -{ -} \ No newline at end of file diff --git a/src/presets/app/app.php b/src/presets/app/app.php deleted file mode 100644 index 05282d5b..00000000 --- a/src/presets/app/app.php +++ /dev/null @@ -1,85 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Presets\Event; - -/** - * Class Event - * @package Bitrix24\Presets\Event - */ -class Event -{ - /** - * @var string event code when bitrix24 application has uninstall - */ - const ON_APP_UNINSTALL = 'ONAPPUNINSTALL'; - /** - * @var string event code when bitrix24 application install - */ - const ON_APP_INSTALL = 'ONAPPINSTALL'; - /** - * @var string event code when bitrix24 application update - */ - const ON_APP_UPDATE = 'ONAPPUPDATE'; - /** - * @var string event code when bitrix24 application payment - */ - const ON_APP_PAYMENT = 'ONAPPPAYMENT'; - /** - * @var string - */ - const ON_APP_TEST = 'ONAPPTEST'; - /** - * @var string event code when task add in bitrix24 - */ - const ON_TASK_ADD = 'ONTASKADD'; - /** - * @var string - */ - const ON_VOXIMPLANT_CALL_INIT = 'ONVOXIMPLANTCALLINIT'; - /** - * @var string - */ - const ON_VOXIMPLANT_CALL_START = 'ONVOXIMPLANTCALLSTART'; - /** - * @var string - */ - const ON_VOXIMPLANT_CALL_END = 'ONVOXIMPLANTCALLEND'; - /** - * @var string event code when task in bitrix24 has update - */ - const ON_TASK_UPDATE = 'ONTASKUPDATE'; - /** - * @var string event code when task in bitrix24 has delete - */ - const ON_TASK_DELETE = 'ONTASKDELETE'; - /** - * @var string - */ - const ON_TASK_COMMENT_ADD = 'ONTASKCOMMENTADD'; - /** - * @var string - */ - const ON_TASK_COMMENT_UPDATE = 'ONTASKCOMMENTUPDATE'; - /** - * @var string - */ - const ON_TASK_COMMENT_DELETE = 'ONTASKCOMMENTDELETE'; - /** - * @var string event code when new user in bitrix24 has added - */ - const ON_USER_ADD = 'ONUSERADD'; - /** - * @var string - */ - const ON_CRM_LEAD_ADD = 'ONCRMLEADADD'; - /** - * @var string - */ - const ON_CRM_LEAD_UPDATE = 'ONCRMLEADUPDATE'; - /** - * @var string - */ - const ON_CRM_LEAD_DELETE = 'ONCRMLEADDELETE'; - /** - * @var string - */ - const ON_CRM_DEAL_ADD = 'ONCRMDEALADD'; - /** - * @var string - */ - const ON_CRM_DEAL_UPDATE = 'ONCRMDEALUPDATE'; - /** - * @var string - */ - const ON_CRM_DEAL_DELETE = 'ONCRMDEALDELETE'; - /** - * @var string - */ - const ON_CRM_COMPANY_ADD = 'ONCRMCOMPANYADD'; - /** - * @var string - */ - const ON_CRM_COMPANY_UPDATE = 'ONCRMCOMPANYUPDATE'; - /** - * @var string - */ - const ON_CRM_COMPANY_DELETE = 'ONCRMCOMPANYDELETE'; - /** - * @var string - */ - const ON_CRM_CONTACT_ADD = 'ONCRMCONTACTADD'; - /** - * @var string - */ - const ON_CRM_CONTACT_UPDATE = 'ONCRMCONTACTUPDATE'; - /** - * @var string - */ - const ON_CRM_CONTACT_DELETE = 'ONCRMCONTACTDELETE'; - /** - * @var string - */ - const ON_CRM_CURRENCY_ADD = 'ONCRMCURRENCYADD'; - /** - * @var string - */ - const ON_CRM_CURRENCY_UPDATE = 'ONCRMCURRENCYUPDATE'; - /** - * @var string - */ - const ON_CRM_CURRENCY_DELETE = 'ONCRMCURRENCYDELETE'; - /** - * @var string - */ - const ON_CRM_PRODUCT_ADD = 'ONCRMPRODUCTADD'; - /** - * @var string - */ - const ON_CRM_PRODUCT_UPDATE = 'ONCRMPRODUCTUPDATE'; - /** - * @var string - */ - const ON_CRM_PRODUCT_DELETE = 'ONCRMPRODUCTDELETE'; - /** - * @var string - */ - const ON_CRM_ACTIVITY_ADD = 'ONCRMACTIVITYADD'; - /** - * @var string - */ - const ON_CRM_ACTIVITY_UPDATE = 'ONCRMACTIVITYUPDATE'; - /** - * @var string - */ - const ON_CRM_ACTIVITY_DELETE = 'ONCRMACTIVITYDELETE'; - /** - * @var string - */ - const ON_CRM_QUOTE_ADD = 'ONCRMQUOTEADD'; - /** - * @var string - */ - const ON_CRM_QUOTE_UPDATE = 'ONCRMQUOTEUPDATE'; - /** - * @var string - */ - const ON_CRM_QUOTE_DELETE = 'ONCRMQUOTEDELETE'; - /** - * @var string event on bot add to chat or private chat - */ - const ON_IM_BOT_JOIN_CHAT = 'ONIMBOTJOINCHAT'; - /** - * @var string event on bot delete - */ - const ON_IM_BOT_DELETE = 'ONIMBOTDELETE'; - /** - * @var string event on bot gets message - */ - const ON_IM_BOT_MESSAGE_ADD = 'ONIMBOTMESSAGEADD'; - /** - * @var string event on bot gets command - */ - const ON_IM_COMMAND_ADD = 'ONIMCOMMANDADD'; -} diff --git a/src/presets/event/fields.php b/src/presets/event/fields.php deleted file mode 100644 index cf7056b9..00000000 --- a/src/presets/event/fields.php +++ /dev/null @@ -1,29 +0,0 @@ - and contributors - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Presets\Im; - -/** - * Interface iChatColor - * @package Bitrix24\Presets\Im - */ -interface iChatColor -{ - /** - * @var string chat color in mobile - */ - const RED = '#FF0000'; - /** - * @var string chat color in mobile - */ - const GREEN = '#008000'; - /** - * @var string chat color in mobile - */ - const MINT = '#98ff98'; - /** - * @var string chat color in mobile - */ - const LIGHT_BLUE = '#add8e6'; - /** - * @var string chat color in mobile - */ - const DARK_BLUE = '#00008b'; - /** - * @var string chat color in mobile - */ - const PURPLE = '#800080'; - /** - * @var string chat color in mobile - */ - const AQUA = '#00ffff'; - /** - * @var string chat color in mobile - */ - const PINK = '#ffc0cb'; - /** - * @var string chat color in mobile - */ - const LIME = '#bfff00'; - /** - * @var string chat color in mobile - */ - const BROWN = '#a52a2a'; - /** - * @var string chat color in mobile - */ - const AZURE = '#007fff'; - /** - * @var string chat color in mobile - */ - const KHAKI = '#c3b091'; - /** - * @var string chat color in mobile - */ - const SAND = '#c2b280'; - /** - * @var string chat color in mobile - */ - const MARENGO = '#4C5866'; - /** - * @var string chat color in mobile - */ - const GRAY = '#808080'; - /** - * @var string chat color in mobile - */ - const GRAPHITE = '#383428'; -} \ No newline at end of file diff --git a/src/presets/lang.php b/src/presets/lang.php deleted file mode 100644 index 991c5b0f..00000000 --- a/src/presets/lang.php +++ /dev/null @@ -1,41 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24\Presets; - -/** - * Class Scope - * @package Bitrix24\Presets - */ -class Scope -{ - /** - * @var string work with business process - */ - const BIZPROC = 'bizproc'; - - /** - * @var string work with calendar - */ - const CALENDAR = 'calendar'; - - /** - * @var string work with CRM - */ - const CRM = 'crm'; - - /** - * @var string work with bitrix24 disk - */ - const DISK = 'disk'; - - /** - * @var string work with departments - */ - const DEPARTMENT = 'department'; - - /** - * @var string work with B24 entity - */ - const ENTITY = 'entity'; - - /** - * @var string work with IM - */ - const IM = 'im'; - - /** - * @var string work with IM bot - */ - const IMBOT = 'imbot'; - - /** - * @var string work with users - */ - const USER = 'user'; - - /** - * @var string work with mail - */ - const MAILSERVICE = 'mailservice'; - - /** - * @var string work with task - */ - const TASK = 'task'; - - /** - * @var string work with task extended - */ - const TASKS_EXTENDED = 'tasks_extended'; - - /** - * @var string work with telephony - */ - const TELEPHONY = 'telephony'; - - /** - * @var string work with life line - */ - const LOG = 'log'; - - /** - * @var string work with sonet group - */ - const SONET_GROUP = 'sonet_group'; - - /** - * @var string work with lists - */ - const LISTS = 'lists'; - - /** - * @var string work with placement - */ - const PLACEMENT = 'placement'; -} \ No newline at end of file diff --git a/src/presets/task/item/fields.php b/src/presets/task/item/fields.php deleted file mode 100644 index a46e720d..00000000 --- a/src/presets/task/item/fields.php +++ /dev/null @@ -1,216 +0,0 @@ -getTags() will return an array of the tag names. - */ - const TAGS ='TAGS'; - /** - * @var string A boolean (Y/N) value which, if set to "Y", specifies that a responsible person associated with the task is allowed to shift the deadline date. Read, write - */ - const ALLOW_CHANGE_DEADLINE = 'ALLOW_CHANGE_DEADLINE'; - /** - * @var string A boolean (Y/N) value which, if set to "Y", specifies that the task result needs to be approved by a creator. Otherwise, the task will auto close once marked as completed. Read, write - */ - const TASK_CONTROL = 'TASK_CONTROL'; - /** - * @var string Specifies the ID of a parent task. Read, write - */ - const PARENT_ID = 'PARENT_ID'; - /** - * @var string Specifies the ID of a task that needs to be completed prior to this one. Read, write - */ - const DEPENDS_ON = 'DEPENDS_ON'; - /** - * @var string Specifies the ID of a workgroup to which this task relates. Read, write - */ - const GROUP_ID = 'GROUP_ID'; - /** - * @var string The user ID of a person to whom the task is assigned. Read, write - */ - const RESPONSIBLE_ID = 'RESPONSIBLE_ID'; - /** - * @var string Specifies a time estimate for the task. Read, write - */ - const TIME_ESTIMATE = 'TIME_ESTIMATE'; - /** - * @var integer The current task ID. The identifier is unique across the database. Read - */ - const ID = 'ID'; - /** - * @var integer Specifies the user ID of a person who created the task. Read, write - */ - const CREATED_BY = 'CREATED_BY'; - /** - * @var string A boolean (Y/N) value which, if set to "Y", specifies that the task description includes BB codes. Read - */ - const DESCRIPTION_IN_BBCODE = 'DESCRIPTION_IN_BBCODE'; - /** - * @var string A text description of the reason for rejecting the task. Read, write - */ - const DECLINE_REASON = 'DECLINE_REASON'; - /** - * @var string Determines the task's real status set using the STATUS field (see CTasks::STATE_xxx). This field is read-only. - */ - const REAL_STATUS = 'REAL_STATUS'; - /** - * @var string Use this field to set the meta status for a task. Read, write - * To set this field, use the CTasks::STATE_xxx constants. However, this field may return one of the CTasks::METASTATE_xxx values. - * For example, if a task had never been started and became overdue, this field will return CTasks::METASTATE_EXPIRED, - * while the real status is CTasks::STATE_NEW returned by the REAL_STATUS field. - */ - const STATUS = 'STATUS'; - /** - * @var string Contains the first name of a person to whom the task is assigned (a responsible person). Read - */ - const RESPONSIBLE_NAME = 'RESPONSIBLE_NAME'; - /** - * @var string The last name of the task's responsible person. Read - */ - const RESPONSIBLE_LAST_NAME = 'RESPONSIBLE_LAST_NAME'; - /** - * @var string The second name of the task's responsible person. Read - */ - const RESPONSIBLE_SECOND_NAME = 'RESPONSIBLE_SECOND_NAME'; - /** - * @var \DateTime Specifies the date the task was started. Read - */ - const DATE_START = 'DATE_START'; - /** - * @var string Specifies the time required to complete the task, in minutes. Read - */ - const DURATION_FACT = 'DURATION_FACT'; - /** - * @var string Contains the first name of a person who created the task. Read - */ - const CREATED_BY_NAME = 'CREATED_BY_NAME'; - /** - * @var string The last name of the task creator. Read - */ - const CREATED_BY_LAST_NAME = 'CREATED_BY_LAST_NAME'; - /** - * @var string The second name of the task creator. Read - */ - const CREATED_BY_SECOND_NAME = 'CREATED_BY_SECOND_NAME'; - /** - * @var string Specifies the date the task was created. Read - */ - const CREATED_DATE = 'CREATED_DATE'; - /** - * @var string The user ID of a person who last updated the task. Read - */ - const CHANGED_BY = 'CHANGED_BY'; - /** - * @var string Specifies the date the task was last updated. Read - */ - const CHANGED_DATE = 'CHANGED_DATE'; - /** - * @var string The user ID of a person who changed the task status. Read - */ - const STATUS_CHANGED_BY = 'STATUS_CHANGED_BY'; - /** - * @var string Specifies the date the task status was changed. Read - */ - const STATUS_CHANGED_DATE = 'STATUS_CHANGED_DATE'; - /** - * @var string The user ID of a person who completed the task. Read - */ - const CLOSED_BY = 'CLOSED_BY'; - /** - * @var string Specifies the date the task was completed. Read - */ - const CLOSED_DATE = 'CLOSED_DATE'; - /** - * @var string A GUID (globally unique identifier) associated with the task. It can be said, with a fair amount of confidence, - * that this identifier will always remain unique across multiple databases. Read - */ - const GUID = 'GUID'; - /** - * @var string The rating score given by a task creator. Read, write - */ - const MARK ='MARK'; - /** - * @var string Contains the date the task was last viewed in the public area by a currently logged in user. Read - */ - const VIEWED_DATE = 'VIEWED_DATE'; - /** - * @var string Specifies the actual time spent for the task, in seconds. Read - */ - const TIME_SPENT_IN_LOGS = 'TIME_SPENT_IN_LOGS'; - /** - * @var string Specifies the task external ID. Read, write - */ - const XML_ID = 'XML_ID'; - /** - * @var string A boolean (Y/N) value which, if set to "Y", specifies that the system keeps tracking of the time spent for the task. Read, write - */ - const ALLOW_TIME_TRACKING ='ALLOW_TIME_TRACKING'; - /** - * @var string A boolean (Y/N) value which, if set to "Y", includes the task in the performance report. Read, write - */ - const ADD_IN_REPORT = 'ADD_IN_REPORT'; - /** - * @var string Specifies the ID of the forum containing comments to the task. Read, write - */ - const FORUM_ID = 'FORUM_ID'; - /** - * @var string Specifies the ID of the forum topic containing comments to the task. Read, write - */ - const FORUM_TOPIC_ID = 'FORUM_TOPIC_ID'; - /** - * @var string Contains the number of forum comments. Read - */ - const COMMENTS_COUNT ='COMMENTS_COUNT'; - /** - * @var string Specifies the ID of the site on which the task was created. Read, write - */ - const SITE_ID = 'SITE_ID'; - /** - * @var string A boolean (Y/N) value which, if set to "Y", specifies that at least one of the task participants is subordinate to a current user. Read - */ - const SUBORDINATE = 'SUBORDINATE'; - /** - * @var string Contains the ID of a template used to create the task. This field may be empty for tasks created in outdated versions. Read - */ - const FORKED_BY_TEMPLATE_ID = 'FORKED_BY_TEMPLATE_ID'; -} \ No newline at end of file diff --git a/src/presets/timing.php b/src/presets/timing.php deleted file mode 100644 index 61f2b806..00000000 --- a/src/presets/timing.php +++ /dev/null @@ -1,44 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24\Presets; - -/** - * Class Timing - * - * @package Bitrix24\Presets - */ -class Timing -{ - /** - * @var string - */ - const START = 'start'; - /** - * @var string - */ - const FINISH = 'finish'; - /** - * @var string - */ - const DURATION = 'duration'; - /** - * @var string - */ - const PROCESSING = 'processing'; - /** - * @var string - */ - const DATE_START = 'date_start'; - /** - * @var string - */ - const DATE_FINISH = 'date_finish'; -} \ No newline at end of file diff --git a/src/presets/uri.php b/src/presets/uri.php deleted file mode 100644 index 97378bb0..00000000 --- a/src/presets/uri.php +++ /dev/null @@ -1,13 +0,0 @@ - value1, CURLOPT_XXX2 => value2,...) - * - * @return bool - */ - public function setCustomCurlOptions($options) - { - } - - /** - * Return raw request, contain all cURL options array and API query. Data available after you try to call method call - * numbers of array keys is const of cURL module. Example: CURLOPT_RETURNTRANSFER = 19913 - * - * @return array | null - */ - public function getRawRequest() - { - } - - /** - * Return result from function curl_getinfo. Data available after you try to call method call - * - * @return array | null - */ - public function getRequestInfo() - { - } - - /** - * Return additional parameters of last api-call. Data available after you try to call method call - * - * @return array | null - */ - public function getMethodParameters() - { - } - - /** - * Execute Bitrix24 REST API method - * - * @param string $methodName - * @param array $additionalParameters - * - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24TokenIsInvalidException - * @throws Bitrix24TokenIsExpiredException - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24PaymentRequiredException - * @throws Bitrix24SecurityException - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * - * @return array - */ - public function call($methodName, array $additionalParameters = array()) - { - } - - /** - * Get raw response from Bitrix24 before json_decode call, method available only in debug mode. - * To activate debug mode you must before set to true flag isSaveRawResponse in class construct - * - * @throws Bitrix24Exception - * - * @return string - */ - public function getRawResponse() - { - } - - /** - * Get new access token - * - * @return array - * - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * @throws Bitrix24TokenIsInvalidException - * @throws Bitrix24TokenIsExpiredException - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24PaymentRequiredException - * - */ - public function getNewAccessToken() - { - } - - /** - * Authorize and get first access token - * - * @param $code - * - * @return array - * - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * @throws Bitrix24TokenIsInvalidException - * @throws Bitrix24TokenIsExpiredException - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24PaymentRequiredException - * - */ - public function getFirstAccessToken($code) - { - } - - /** - * Check is access token expire, call list of all available api-methods from B24 portal with current access token - * if we have an error code expired_token then return true else return false - * - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * @throws Bitrix24TokenIsInvalidException - * @throws Bitrix24TokenIsExpiredException - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24PaymentRequiredException - * - * @return boolean - */ - public function isAccessTokenExpire() - { - } - - /** - * Get list of all methods available for current application - * - * @param array | null $applicationScope - * @param bool $isFull - * - * @return array - * - * @throws Bitrix24Exception - */ - public function getAvailableMethods(array $applicationScope = array(), $isFull = false) - { - } - - /** - * get list of scope for current application from bitrix24 api - * - * @param bool $isFull - * - * @throws Bitrix24Exception - * - * @return array - */ - public function getScope($isFull = false) - { - } - - /** - * set CURL request count retries - * - * @param $retriesCnt - * - * @return boolean - */ - public function setRetriesToConnectCount($retriesCnt = 1) - { - } - - /** - * set retries to connect timeout in microseconds - * - * @param $microseconds - * - * @return boolean - */ - public function setRetriesToConnectTimeout($microseconds = 1000000) - { - } - - /** - * get CURL request count retries - * - * @return int - */ - public function getRetriesToConnectCount() - { - } - - /** - * get retries to connect timeout in microseconds - * - * @return mixed - */ - public function getRetriesToConnectTimeout() - { - } - - /** - * Add call to batch. If [[$callback]] parameter is set, it will receive call result as first parameter. - * - * @param string $method - * @param array $parameters - * @param callable|null $callback - * - * @return string Unique call ID. - */ - public function addBatchCall($method, array $parameters = array(), callable $callback = null) - { - } - - /** - * Return true, if we have unprocessed batch calls. - * - * @return bool - */ - public function hasBatchCalls() - { - } - - /** - * Process batch calls. - * - * @param int $halt Halt batch on error - * @param int $delay Delay between batch calls (in msec) - * - * @throws Bitrix24Exception - * @throws Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - */ - public function processBatchCalls($halt = 0, $delay = self::BATCH_DELAY) - { - } -} - diff --git a/tests/src/Bitrix24Test.php b/tests/src/Bitrix24Test.php deleted file mode 100644 index 5b1198d2..00000000 --- a/tests/src/Bitrix24Test.php +++ /dev/null @@ -1,125 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24; - -use \Psr\Log\NullLogger; - -/** - * Class Bitrix24Test - * @package Bitrix24 - */ -class Bitrix24Test extends \PHPUnit_Framework_TestCase -{ - /** - * @covers Bitrix24::__construct - */ - public function testConstructorWithFirstArgumentIsNotBoolean() - { - $this->setExpectedException('\Bitrix24\Exceptions\Bitrix24Exception'); - $obBitrix24 = new Bitrix24(array()); - } - /** - * @covers Bitrix24::__construct - */ - public function testConstructorWithoutSecondArgument() - { - $obBitrix24 = new Bitrix24(false); - } - /** - * @covers Bitrix24::__construct - */ - public function testConstructorWithStubLogger() - { - $obBitrix24 = new Bitrix24(false, new NullLogger()); - } - /** - * @covers Bitrix24::setMemberId - */ - public function testSetMemberIdWithValidArgument() - { - $obBitrix24 = new Bitrix24(false, new NullLogger()); - $result = $obBitrix24->setMemberId('valid_member_id'); - $this->assertTrue($result); - } - /** - * @covers Bitrix24::setMemberId - */ - public function testSetMemberIdWithNullArgument() - { - $this->setExpectedException('\Bitrix24\Exceptions\Bitrix24Exception'); - $obBitrix24 = new Bitrix24(false, new NullLogger()); - $result = $obBitrix24->setMemberId(null); - $this->assertTrue($result); - } - /** - * @covers Bitrix24::setMemberId - */ - public function testSetMemberIdWithEmptyStringArgument() - { - $this->setExpectedException('\Bitrix24\Exceptions\Bitrix24Exception'); - $obBitrix24 = new Bitrix24(false, new NullLogger()); - $result = $obBitrix24->setMemberId(''); - $this->assertTrue($result); - } - /** - * @covers Bitrix24::setRetriesToConnectCount - */ - public function testSetRetriesToConnectCountWithNull() - { - $this->setExpectedException('\Bitrix24\Exceptions\Bitrix24Exception'); - $obBitrix24 = new Bitrix24(false, new NullLogger()); - $result = $obBitrix24->setRetriesToConnectCount(null); - } - /** - * @covers Bitrix24::setRetriesToConnectCount - */ - public function testSetRetriesToConnectCountWithEmptyArgs() - { - $obBitrix24 = new Bitrix24(false, new NullLogger()); - $result = $obBitrix24->setRetriesToConnectCount(); - $this->assertTrue($result); - } - /** - * @covers Bitrix24::setRetriesToConnectCount - */ - public function testSetRetriesToConnectCountWithValidArgs() - { - $obBitrix24 = new Bitrix24(false, new NullLogger()); - $result = $obBitrix24->setRetriesToConnectCount(1); - $this->assertTrue($result); - } - /** - * @covers Bitrix24::setRetriesToConnectTimeout - */ - public function testSetRetriesToConnectTimeoutWithNull() - { - $this->setExpectedException('\Bitrix24\Exceptions\Bitrix24Exception'); - $obBitrix24 = new Bitrix24(false, new NullLogger()); - $result = $obBitrix24->setRetriesToConnectTimeout(null); - } - /** - * @covers Bitrix24::setRetriesToConnectTimeout - */ - public function testSetRetriesToConnectTimeoutWithEmptyArgs() - { - $obBitrix24 = new Bitrix24(false, new NullLogger()); - $result = $obBitrix24->setRetriesToConnectTimeout(); - $this->assertTrue($result); - } - /** - * @covers Bitrix24::setRetriesToConnectTimeout - */ - public function testSetRetriesToConnectTimeoutWithValidArgs() - { - $obBitrix24 = new Bitrix24(false, new NullLogger()); - $result = $obBitrix24->setRetriesToConnectTimeout(1000000); - $this->assertTrue($result); - } -} \ No newline at end of file diff --git a/tests/src/classes/crm/company/companyTest.php b/tests/src/classes/crm/company/companyTest.php deleted file mode 100644 index cef81745..00000000 --- a/tests/src/classes/crm/company/companyTest.php +++ /dev/null @@ -1,51 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\CRM; - -use Bitrix24\CRM\Company; -use Bitrix24\Contracts\iBitrix24; - - -/** - * @package Bitrix24 - */ -class CompanyTest extends \PHPUnit_Framework_TestCase -{ - public function testUpdateCallsClientWithIdAndFields() - { - $testId = \md5(\time()); - $testField = \md5($testId); - $testFields = [ - $testField => \md5($testField), - ]; - - //silly mocking in PHPUnit 4.8 - $methods = array(); - $ref = new \ReflectionClass('Bitrix24\\Contracts\\iBitrix24'); - foreach ($ref->getMethods() as $method) { - $methods[] = $method->getName(); - } - $client = $this->getMockBuilder('Bitrix24\\Contracts\\iBitrix24') - ->setMethods($methods) - ->getMock(); - $client->expects($this->once()) - ->method('call') - ->with( - 'crm.company.update', - array( - 'id' => $testId, - 'fields' => $testFields, - ) - ); - - $company = new Company($client); - $company->update($testId, $testFields); - } -} diff --git a/tests/src/classes/im/attach/attachTest.php b/tests/src/classes/im/attach/attachTest.php deleted file mode 100644 index 8e947072..00000000 --- a/tests/src/classes/im/attach/attachTest.php +++ /dev/null @@ -1,74 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24; - -use \Bitrix24\Im\Attach\Attach; -use \Psr\Log\NullLogger; - -/** - * Class AttachTest - * @package Bitrix24 - */ -class AttachTest extends \PHPUnit_Framework_TestCase -{ - /** - * @covers \Bitrix24\Im\Attach\Attach::__construct - */ - public function testAttachConstructWithNullArguments() - { - $obItem = new Attach(null, null); - } - - /** - * @covers \Bitrix24\Im\Attach\Attach::setStatusNormal - */ - public function testAttachSetStatusNormal() - { - $obItem = new Attach(null, null); - $obItem->setStatusNormal(); - } - - /** - * @covers \Bitrix24\Im\Attach\Attach::setStatusAttention - */ - public function testAttachSetStatusAttention() - { - $obItem = new Attach(null, null); - $obItem->setStatusAttention(); - } - - /** - * @covers \Bitrix24\Im\Attach\Attach::setStatusProblem - */ - public function testAttachSetStatusProblem() - { - $obItem = new Attach(null, null); - $obItem->setStatusProblem(); - } - - /** - * @covers \Bitrix24\Im\Attach\Attach::getData - */ - public function testAttachGetData() - { - $obItem = new Attach(null, null); - $obItem->getData(); - } - - /** - * @covers \Bitrix24\Im\Attach\Attach::getAttachItems - */ - public function testAttachGetAttachItems() - { - $obItem = new Attach(null, null); - $obItem->getAttachItems(); - } -} \ No newline at end of file diff --git a/tests/src/classes/im/attach/item/delimiterTest.php b/tests/src/classes/im/attach/item/delimiterTest.php deleted file mode 100644 index 50ab0e10..00000000 --- a/tests/src/classes/im/attach/item/delimiterTest.php +++ /dev/null @@ -1,30 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24; - -use \Bitrix24\Im\Attach\Item\Delimiter; -use \Psr\Log\NullLogger; - -/** - * Class DelimiterTest - * @package Bitrix24 - */ -class DelimiterTest extends \PHPUnit_Framework_TestCase -{ - /** - * @covers \Bitrix24\Im\Attach\Item\Delimiter::getAttachTypeCode - */ - public function testDelimiterTypeCode() - { - $obItem = new Delimiter(); - $this->assertSame($obItem->getAttachTypeCode(), 'DELIMITER'); - } -} \ No newline at end of file diff --git a/tests/src/classes/im/attach/item/fileTest.php b/tests/src/classes/im/attach/item/fileTest.php deleted file mode 100644 index ae443591..00000000 --- a/tests/src/classes/im/attach/item/fileTest.php +++ /dev/null @@ -1,30 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24; - -use \Bitrix24\Im\Attach\Item\File; -use \Psr\Log\NullLogger; - -/** - * Class FileTest - * @package Bitrix24 - */ -class FileTest extends \PHPUnit_Framework_TestCase -{ - /** - * @covers \Bitrix24\Im\Attach\Item\File::getAttachTypeCode - */ - public function testFileTypeCode() - { - $obItem = new File(null, null, null); - $this->assertSame($obItem->getAttachTypeCode(), 'FILE'); - } -} \ No newline at end of file diff --git a/tests/src/classes/im/attach/item/gridTest.php b/tests/src/classes/im/attach/item/gridTest.php deleted file mode 100644 index 8d073740..00000000 --- a/tests/src/classes/im/attach/item/gridTest.php +++ /dev/null @@ -1,30 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24; - -use \Bitrix24\Im\Attach\Item\Grid; -use \Psr\Log\NullLogger; - -/** - * Class GridTest - * @package Bitrix24 - */ -class GridTest extends \PHPUnit_Framework_TestCase -{ - /** - * @covers \Bitrix24\Im\Attach\Item\Grid::getAttachTypeCode - */ - public function testGridTypeCode() - { - $obItem = new Grid(); - $this->assertSame($obItem->getAttachTypeCode(), 'GRID'); - } -} \ No newline at end of file diff --git a/tests/src/classes/im/attach/item/imageTest.php b/tests/src/classes/im/attach/item/imageTest.php deleted file mode 100644 index 94174095..00000000 --- a/tests/src/classes/im/attach/item/imageTest.php +++ /dev/null @@ -1,30 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24; - -use \Bitrix24\Im\Attach\Item\Image; -use \Psr\Log\NullLogger; - -/** - * Class ImageTest - * @package Bitrix24 - */ -class ImageTest extends \PHPUnit_Framework_TestCase -{ - /** - * @covers \Bitrix24\Im\Attach\Item\Image::getAttachTypeCode - */ - public function testImageTypeCode() - { - $obItem = new Image(null, null); - $this->assertSame($obItem->getAttachTypeCode(), 'IMAGE'); - } -} \ No newline at end of file diff --git a/tests/src/classes/im/attach/item/linkTest.php b/tests/src/classes/im/attach/item/linkTest.php deleted file mode 100644 index 8b021815..00000000 --- a/tests/src/classes/im/attach/item/linkTest.php +++ /dev/null @@ -1,30 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24; - -use \Bitrix24\Im\Attach\Item\Link; -use \Psr\Log\NullLogger; - -/** - * Class LinkTest - * @package Bitrix24 - */ -class LinkTest extends \PHPUnit_Framework_TestCase -{ - /** - * @covers \Bitrix24\Im\Attach\Item\Link::getAttachTypeCode - */ - public function testLinkTypeCode() - { - $obItem = new Link(null, null, null, null); - $this->assertSame($obItem->getAttachTypeCode(), 'LINK'); - } -} \ No newline at end of file diff --git a/tests/src/classes/im/attach/item/messageTest.php b/tests/src/classes/im/attach/item/messageTest.php deleted file mode 100644 index 1693eefd..00000000 --- a/tests/src/classes/im/attach/item/messageTest.php +++ /dev/null @@ -1,30 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24; - -use \Bitrix24\Im\Attach\Item\Message; -use \Psr\Log\NullLogger; - -/** - * Class MessageTest - * @package Bitrix24 - */ -class MessageTest extends \PHPUnit_Framework_TestCase -{ - /** - * @covers \Bitrix24\Im\Attach\Item\Message::getAttachTypeCode - */ - public function testUserListWithNullArgument() - { - $obItem = new Message('Test message'); - $this->assertSame($obItem->getAttachTypeCode(), 'MESSAGE'); - } -} \ No newline at end of file diff --git a/tests/src/classes/im/attach/item/userTest.php b/tests/src/classes/im/attach/item/userTest.php deleted file mode 100644 index 72999dc6..00000000 --- a/tests/src/classes/im/attach/item/userTest.php +++ /dev/null @@ -1,30 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24; - -use \Bitrix24\Im\Attach\Item\User; -use \Psr\Log\NullLogger; - -/** - * Class UserTest - * @package Bitrix24 - */ -class UserTest extends \PHPUnit_Framework_TestCase -{ - /** - * @covers \Bitrix24\Im\Attach\Item\User::getAttachTypeCode - */ - public function testUserTypeCode() - { - $obItem = new User(null); - $this->assertSame($obItem->getAttachTypeCode(), 'USER'); - } -} \ No newline at end of file diff --git a/tests/src/classes/im/chatTest.php b/tests/src/classes/im/chatTest.php deleted file mode 100644 index c6f8f4cf..00000000 --- a/tests/src/classes/im/chatTest.php +++ /dev/null @@ -1,268 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24; - -use \Bitrix24\Im\Chat; -use \Bitrix24\Contracts\iBitrix24; -use \Bitrix24\Stub\Bitrix24 as Bitrix24NullObject; - -use \Psr\Log\NullLogger; - -/** - * Class ChatTest - * @package Bitrix24 - */ -class ChatTest extends \PHPUnit_Framework_TestCase -{ - /** - * @var iBitrix24 - */ - protected $bitrix24App; - - /** - * @var int - */ - protected $defaultChatId; - - /** - * @return void - */ - protected function setUp() - { - $this->bitrix24App = new Bitrix24NullObject(); - $this->defaultChatId = 1; - } - - /** - * @covers \Bitrix24\Im\Chat::userList - */ - public function testUserListWithNullArgument() - { - $obChat = new Chat($this->bitrix24App); - $obChat->userList(null); - } - - /** - * @covers \Bitrix24\Im\Chat::userList - */ - public function testUserListWithNumericArgument() - { - $obChat = new Chat($this->bitrix24App); - $obChat->userList($this->defaultChatId); - } - - /** - * @covers \Bitrix24\Im\Chat::add - */ - public function testAddChatWithTitleAndDescription() - { - $obChat = new Chat($this->bitrix24App); - $obChat->add('chat title', 'chat description'); - } - - /** - * @covers \Bitrix24\Im\Chat::delete - */ - public function testDeleteWithNullArgument() - { - $obChat = new Chat($this->bitrix24App); - $obChat->delete(null); - } - - /** - * @covers \Bitrix24\Im\Chat::delete - */ - public function testDeleteWithNumericArgument() - { - $obChat = new Chat($this->bitrix24App); - $obChat->delete($this->defaultChatId); - } - - /** - * @covers \Bitrix24\Im\Chat::setOwner - */ - public function testSetOwnerWithNullChatId() - { - $obChat = new Chat($this->bitrix24App); - $obChat->setOwner(null, $this->defaultChatId); - } - - /** - * @covers \Bitrix24\Im\Chat::setOwner - */ - public function testSetOwnerWithNullUserId() - { - $obChat = new Chat($this->bitrix24App); - $obChat->setOwner($this->defaultChatId, null); - } - - /** - * @covers \Bitrix24\Im\Chat::setOwner - */ - public function testSetOwnerWithValidArguments() - { - $obChat = new Chat($this->bitrix24App); - $obChat->setOwner($this->defaultChatId, 1); - } - - /** - * @covers \Bitrix24\Im\Chat::updateColor - */ - public function testUpdateColorWithValidArguments() - { - $obChat = new Chat($this->bitrix24App); - $obChat->updateColor($this->defaultChatId, 'RED'); - } - - /** - * @covers \Bitrix24\Im\Chat::updateColor - */ - public function testUpdateColorWithNullChatId() - { - $obChat = new Chat($this->bitrix24App); - $obChat->updateColor(null, 'RED'); - } - - /** - * @covers \Bitrix24\Im\Chat::updateColor - */ - public function testUpdateColorWithNullColor() - { - $obChat = new Chat($this->bitrix24App); - $obChat->updateColor($this->defaultChatId, null); - } - - /** - * @covers \Bitrix24\Im\Chat::updateTitle - */ - public function testUpdateTitleWithValidArguments() - { - $obChat = new Chat($this->bitrix24App); - $obChat->updateTitle($this->defaultChatId, 'test title'); - } - - /** - * @covers \Bitrix24\Im\Chat::updateTitle - */ - public function testUpdateTitleWithNullChatId() - { - $obChat = new Chat($this->bitrix24App); - $obChat->updateTitle(null, 'test title'); - } - - /** - * @covers \Bitrix24\Im\Chat::updateTitle - */ - public function testUpdateTitleWithNullTitle() - { - $obChat = new Chat($this->bitrix24App); - $obChat->updateTitle($this->defaultChatId, null); - } - - /** - * @covers \Bitrix24\Im\Chat::updateAvatar - */ - public function testUpdateAvatarWithValidArguments() - { - $obChat = new Chat($this->bitrix24App); - $obChat->updateAvatar($this->defaultChatId, 'test avatar'); - } - - /** - * @covers \Bitrix24\Im\Chat::updateAvatar - */ - public function testUpdateAvatarWithNullChatId() - { - $obChat = new Chat($this->bitrix24App); - $obChat->updateAvatar(null, 'test avatar'); - } - - /** - * @covers \Bitrix24\Im\Chat::updateAvatar - */ - public function testUpdateAvatarWithNullAvatar() - { - $obChat = new Chat($this->bitrix24App); - $obChat->updateAvatar($this->defaultChatId, null); - } - - /** - * @covers \Bitrix24\Im\Chat::sendTyping - */ - public function testSendTypingWithValidArguments() - { - $obChat = new Chat($this->bitrix24App); - $obChat->sendTyping($this->defaultChatId); - } - - /** - * @covers \Bitrix24\Im\Chat::sendTyping - */ - public function testSendTypingWithNullChatId() - { - $obChat = new Chat($this->bitrix24App); - $obChat->sendTyping(null); - } - - /** - * @covers \Bitrix24\Im\Chat::userDelete - */ - public function testUserDeleteWithValidArguments() - { - $obChat = new Chat($this->bitrix24App); - $obChat->userDelete($this->defaultChatId, 1); - } - - /** - * @covers \Bitrix24\Im\Chat::userDelete - */ - public function testUserDeleteWithNullChatId() - { - $obChat = new Chat($this->bitrix24App); - $obChat->userDelete(null, 1); - } - - /** - * @covers \Bitrix24\Im\Chat::userDelete - */ - public function testUserDeleteWithNullUserId() - { - $obChat = new Chat($this->bitrix24App); - $obChat->userDelete($this->defaultChatId, null); - } - - /** - * @covers \Bitrix24\Im\Chat::userAdd - */ - public function testUserAddWithValidArguments() - { - $obChat = new Chat($this->bitrix24App); - $obChat->userAdd($this->defaultChatId, array(2, 3, 4)); - } - - /** - * @covers \Bitrix24\Im\Chat::userAdd - */ - public function testUserAddWithNullChatId() - { - $obChat = new Chat($this->bitrix24App); - $obChat->userAdd(null, array(2, 3, 4)); - } - - /** - * @covers \Bitrix24\Im\Chat::userAdd - */ - public function testUserAddWithEmptyArray() - { - $obChat = new Chat($this->bitrix24App); - $obChat->userAdd($this->defaultChatId, array()); - } -} \ No newline at end of file From 783fc0ac8025b1caaf42744ddd7892e33e051356 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 19 Oct 2020 00:41:19 +0300 Subject: [PATCH 155/647] v2 dev 2 - add scope --- .gitignore | 3 +- phpunit.xml.dist | 29 ++++--- src/Core/Credentials/Scope.php | 78 +++++++++++++++++-- src/Core/Exceptions/BaseException.php | 14 ++++ .../Exceptions/InvalidArgumentException.php | 14 ++++ .../Exceptions/UnknownScopeCodeException.php | 14 ++++ tests/Unit/Core/Credentials/ScopeTest.php | 75 ++++++++++++++++++ tests/bootstrap.php | 14 +--- 8 files changed, 211 insertions(+), 30 deletions(-) create mode 100644 src/Core/Exceptions/BaseException.php create mode 100644 src/Core/Exceptions/InvalidArgumentException.php create mode 100644 src/Core/Exceptions/UnknownScopeCodeException.php create mode 100644 tests/Unit/Core/Credentials/ScopeTest.php diff --git a/.gitignore b/.gitignore index 84873cd7..f62d901e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /.idea* vendor composer.phar -composer.lock \ No newline at end of file +composer.lock +.phpunit.result.cache \ No newline at end of file diff --git a/phpunit.xml.dist b/phpunit.xml.dist index e3c57095..702c2300 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,16 +1,23 @@ - - + + + + ./src + + + + + - - tests/src/ + + ./tests/ - - - src/ - - diff --git a/src/Core/Credentials/Scope.php b/src/Core/Credentials/Scope.php index c5ec8e2e..1c89fdd0 100644 --- a/src/Core/Credentials/Scope.php +++ b/src/Core/Credentials/Scope.php @@ -4,6 +4,8 @@ namespace Bitrix24\SDK\Core\Credentials; +use Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException; + /** * Class Scope * @@ -11,18 +13,78 @@ */ class Scope { - public function __construct() - { - } + /** + * @var string[] + */ + protected $availableScope = [ + 'bizproc', + 'calendar', + 'call', + 'contact_center', + 'crm', + 'delivery', + 'department', + 'disk', + 'documentgenerator', + 'entity', + 'faceid', + 'forum', + 'im', + 'imbot', + 'imopenlines', + 'intranet', + 'landing', + 'landing_cloud', + 'lists', + 'log', + 'mailservice', + 'messageservice', + 'mobile', + 'pay_system', + 'placement', + 'pull', + 'pull_channel', + 'rating', + 'sale', + 'smile', + 'sonet_group', + 'task', + 'tasks_extended', + 'telephony', + 'timeman', + 'user', + 'userconsent', + ]; - public function withCrm(): self + /** + * @var array + */ + protected $currentScope = []; + + /** + * Scope constructor. + * + * @param array $scope + * + * @throws UnknownScopeCodeException + */ + public function __construct(array $scope = []) { - return $this; - } + array_change_key_case($scope, CASE_LOWER); + foreach ($scope as $item) { + if (!in_array($item, $this->availableScope, true)) { + throw new UnknownScopeCodeException(sprintf('unknown application scope code - %s', $item)); + } + } + $this->currentScope = $scope; + } - public function build(): array + /** + * @return array + */ + public function getScopeCodes(): array { - return []; + return array_unique($this->currentScope); } } \ No newline at end of file diff --git a/src/Core/Exceptions/BaseException.php b/src/Core/Exceptions/BaseException.php new file mode 100644 index 00000000..bb5fe834 --- /dev/null +++ b/src/Core/Exceptions/BaseException.php @@ -0,0 +1,14 @@ +assertEquals($availableScope, $scope->getScopeCodes()); + } + + /** + * @throws UnknownScopeCodeException + */ + public function testUnknownScope(): void + { + $this->expectException(UnknownScopeCodeException::class); + + $scope = new Scope(['fooo']); + } +} diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 659a7d60..0588c285 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,11 +1,5 @@ - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -require __DIR__ . "/../vendor/autoload.php"; -date_default_timezone_set('UTC'); + +declare(strict_types=1); + +require_once \dirname(__DIR__) . '/vendor/autoload.php'; From 2a18153fd6257e5d16bb08947afc0e4d04a3b084 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 19 Oct 2020 00:52:55 +0300 Subject: [PATCH 156/647] v2 dev 2 - add scope --- src/Core/Credentials/Scope.php | 5 +++-- tests/Unit/Core/Credentials/ScopeTest.php | 10 ++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/Core/Credentials/Scope.php b/src/Core/Credentials/Scope.php index 1c89fdd0..9962ea06 100644 --- a/src/Core/Credentials/Scope.php +++ b/src/Core/Credentials/Scope.php @@ -70,7 +70,8 @@ class Scope */ public function __construct(array $scope = []) { - array_change_key_case($scope, CASE_LOWER); + $scope = array_map('strtolower', $scope); + array_unique($scope); foreach ($scope as $item) { if (!in_array($item, $this->availableScope, true)) { throw new UnknownScopeCodeException(sprintf('unknown application scope code - %s', $item)); @@ -85,6 +86,6 @@ public function __construct(array $scope = []) */ public function getScopeCodes(): array { - return array_unique($this->currentScope); + return $this->currentScope; } } \ No newline at end of file diff --git a/tests/Unit/Core/Credentials/ScopeTest.php b/tests/Unit/Core/Credentials/ScopeTest.php index 3d82d9b5..5ffd952d 100644 --- a/tests/Unit/Core/Credentials/ScopeTest.php +++ b/tests/Unit/Core/Credentials/ScopeTest.php @@ -72,4 +72,14 @@ public function testUnknownScope(): void $scope = new Scope(['fooo']); } + + /** + * @throws UnknownScopeCodeException + */ + public function testWrongScopeCode(): void + { + $scope = new Scope(['CRM', 'Call', 'im']); + + $this->assertEquals(['crm', 'call', 'im'], $scope->getScopeCodes()); + } } From 19243cf8a7f7a6ec73c6be500c703e031a8d022b Mon Sep 17 00:00:00 2001 From: gilyazov Date: Mon, 26 Oct 2020 17:16:09 +0300 Subject: [PATCH 157/647] =?UTF-8?q?=D1=80=D0=B5=D0=B6=D0=B5=D1=82=20=D0=B3?= =?UTF-8?q?=D0=BB=D0=B0=D0=B7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Табуляция --- src/classes/crm/contact/contact.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/classes/crm/contact/contact.php b/src/classes/crm/contact/contact.php index ded8e1d3..33214523 100644 --- a/src/classes/crm/contact/contact.php +++ b/src/classes/crm/contact/contact.php @@ -42,9 +42,9 @@ public function add($fields = array(), $params = array()) $fullResult = $this->client->call( 'crm.contact.add', array( - 'fields' => $fields, - 'params' => $params - ) + 'fields' => $fields, + 'params' => $params + ) ); return $fullResult; } From 6f19e897ade5f4aa0f224c88adfd6af5b8bc7eb1 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 31 Oct 2020 01:08:15 +0300 Subject: [PATCH 158/647] add webhook docs --- .travis.yml | 9 +-- CHANGELOG.md | 2 +- README.md | 26 +++++++ docs/EN/Core/Auth/auth.md | 38 ++++++++++ docs/EN/documentation.md | 5 ++ docs/RU/Core/Auth/auth.md | 38 ++++++++++ docs/RU/documentation.md | 5 ++ src/Core/Credentials/Credentials.php | 15 +++- src/Core/Credentials/WebhookUrl.php | 5 +- src/Core/Response/DTO/Response.php | 50 +++++++++++++ src/Core/Response/DTO/Result.php | 36 +++++++++ src/Core/Response/DTO/Time.php | 107 +++++++++++++++++++++++++++ src/Core/Response/Response.php | 76 +++++++++++++++++++ 13 files changed, 399 insertions(+), 13 deletions(-) create mode 100644 docs/EN/Core/Auth/auth.md create mode 100644 docs/EN/documentation.md create mode 100644 docs/RU/Core/Auth/auth.md create mode 100644 docs/RU/documentation.md create mode 100644 src/Core/Response/DTO/Response.php create mode 100644 src/Core/Response/DTO/Result.php create mode 100644 src/Core/Response/DTO/Time.php create mode 100644 src/Core/Response/Response.php diff --git a/.travis.yml b/.travis.yml index f115c2c6..73edc3d5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,17 +1,10 @@ language: php php: - - 7.0 - 7.1 - 7.2 - 7.3 - - 7.4snapshot - - hhvm - -matrix: - allow_failures: - - php: 5.3.3 - - php: hhvm + - 7.4 sudo: false diff --git a/CHANGELOG.md b/CHANGELOG.md index 95329f81..350ce915 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ # bitrix24-php-sdk change log ## 2.0 DEV * remove all old code - +* add documentation webhook auth type ## 0.7.0 (11.07.2020) * add arguments in method `Bitrix24\Bizproc\Robot::add` for return results support diff --git a/README.md b/README.md index bd09c490..d071353a 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ A powerful PHP library for the Bitrix24 REST API [Bitrix24 API documentation - English](https://training.bitrix24.com/rest_help/) [Register new Bitrix24 account](https://www.bitrix24.ru/create.php?p=255670) + Bitrix24 auth features - work with auth tokens - work with incoming webhooks @@ -22,7 +23,32 @@ API - level features - 3.2 offline queues - 3.3 add change domain URL support +## SDK Documentation +- [Russian](/docs/RU/documentation.md) +- [English]() + + ## Architecture + +### Abstraction layers +``` +- http protocol +- json data +- symfony http client +- \Bitrix24\SDK\Core\ApiClient - work with b24 rest-api endpoints + input: arrays \ strings + output: Symfony\Contracts\HttpClient\ResponseInterface, operate with strings + process: network operations +- \Bitrix24\SDK\Services\Main - work with b24 rest-api entities + input: arrays \ strings (?) or queries? + output: b24 response dto + process: b24 entities, operate with +``` + + + + +### File Structure ``` /Core ApiClient.php - default api-client, work on http abstraction layer, return - Symfony\Contracts\HttpClient\ResponseInterface diff --git a/docs/EN/Core/Auth/auth.md b/docs/EN/Core/Auth/auth.md new file mode 100644 index 00000000..f4994018 --- /dev/null +++ b/docs/EN/Core/Auth/auth.md @@ -0,0 +1,38 @@ +Auth with incoming WebHook + +## Documentation +[WebHooks](https://training.bitrix24.com/rest_help/rest_sum/webhooks.php) + +## use web-hooks +1. Create WebHook +2. install bitrix24-php-sdk +3. Configure ApiClient for webhook auth + +```php +pushHandler(new StreamHandler('b24-api-client-debug.log', Logger::DEBUG)); + +$client = HttpClient::create(); + +$credentials = new \Bitrix24\SDK\Core\Credentials\Credentials( + new \Bitrix24\SDK\Core\Credentials\WebhookUrl('https://test.bitrix24.ru/rest/7/9kc3tt3kr7qxjt0c/'), + null, + null +); + +$apiClient = new \Bitrix24\SDK\Core\ApiClient($credentials, $client, $log); + +$result = $apiClient->getResponse('app.info'); +$result = json_decode($result->getContent(), true); +var_dump($result); +``` + diff --git a/docs/EN/documentation.md b/docs/EN/documentation.md new file mode 100644 index 00000000..f1db542e --- /dev/null +++ b/docs/EN/documentation.md @@ -0,0 +1,5 @@ +bitrix24-php-sdk documentation +============================================= + +## Authorisation +- use [incoming webhooks](Core/Auth/auth.md) diff --git a/docs/RU/Core/Auth/auth.md b/docs/RU/Core/Auth/auth.md new file mode 100644 index 00000000..f4e4c287 --- /dev/null +++ b/docs/RU/Core/Auth/auth.md @@ -0,0 +1,38 @@ +Авторизация с использованием «Входящего вебхука» + +## Документация +[Веб-хуки. Быстрый старт](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 +); + +$apiClient = new \Bitrix24\SDK\Core\ApiClient($credentials, $client, $log); + +$result = $apiClient->getResponse('app.info'); +$result = json_decode($result->getContent(), true); +var_dump($result); +``` + diff --git a/docs/RU/documentation.md b/docs/RU/documentation.md new file mode 100644 index 00000000..cf8c4bec --- /dev/null +++ b/docs/RU/documentation.md @@ -0,0 +1,5 @@ +Документация по работе с bitrix24-php-sdk +============================================= + +## Авторизация на портале +- с использованием [входящих веб-хуков](Core/Auth/auth.md) diff --git a/src/Core/Credentials/Credentials.php b/src/Core/Credentials/Credentials.php index a00c9296..714c62ef 100644 --- a/src/Core/Credentials/Credentials.php +++ b/src/Core/Credentials/Credentials.php @@ -11,9 +11,18 @@ */ class Credentials { - protected ?WebhookUrl $webhookUrl; - protected ?OAuthToken $oauthToken; - protected ?string $domainUrl; + /** + * @var WebhookUrl|null + */ + protected $webhookUrl; + /** + * @var OAuthToken|null + */ + protected $oauthToken; + /** + * @var string|null + */ + protected $domainUrl; /** * Credentials constructor. diff --git a/src/Core/Credentials/WebhookUrl.php b/src/Core/Credentials/WebhookUrl.php index c1909c6d..780d9e5c 100644 --- a/src/Core/Credentials/WebhookUrl.php +++ b/src/Core/Credentials/WebhookUrl.php @@ -11,7 +11,10 @@ */ class WebhookUrl { - protected string $url; + /** + * @var string + */ + protected $url; /** * WebHookToken constructor. diff --git a/src/Core/Response/DTO/Response.php b/src/Core/Response/DTO/Response.php new file mode 100644 index 00000000..3afe2383 --- /dev/null +++ b/src/Core/Response/DTO/Response.php @@ -0,0 +1,50 @@ +result = $result; + $this->time = $time; + } + + /** + * @return Time + */ + public function getTime(): Time + { + return $this->time; + } + + /** + * @return Result + */ + public function getResult(): Result + { + return $this->result; + } +} \ No newline at end of file diff --git a/src/Core/Response/DTO/Result.php b/src/Core/Response/DTO/Result.php new file mode 100644 index 00000000..1a56e220 --- /dev/null +++ b/src/Core/Response/DTO/Result.php @@ -0,0 +1,36 @@ +result = $result; + } + + /** + * @return array + */ + public function getResult(): array + { + return $this->result; + } +} \ No newline at end of file diff --git a/src/Core/Response/DTO/Time.php b/src/Core/Response/DTO/Time.php new file mode 100644 index 00000000..0db5501e --- /dev/null +++ b/src/Core/Response/DTO/Time.php @@ -0,0 +1,107 @@ +start = $start; + $this->finish = $finish; + $this->duration = $duration; + $this->processing = $processing; + $this->dateStart = $dateStart; + $this->dateFinish = $dateFinish; + } + + /** + * @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 \DateTimeImmutable + */ + public function getDateStart(): \DateTimeImmutable + { + return $this->dateStart; + } + + /** + * @return \DateTimeImmutable + */ + public function getDateFinish(): \DateTimeImmutable + { + return $this->dateFinish; + } +} \ No newline at end of file diff --git a/src/Core/Response/Response.php b/src/Core/Response/Response.php new file mode 100644 index 00000000..c4107673 --- /dev/null +++ b/src/Core/Response/Response.php @@ -0,0 +1,76 @@ +httpResponse = $httpResponse; + $this->logger = $logger; + } + + /** + * @return ResponseInterface + */ + public function getHttpResponse(): ResponseInterface + { + return $this->httpResponse; + } + + /** + * @return DTO\Response + * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + */ + public function getResponse(): DTO\Response + { + $resultString = $this->httpResponse->getContent(); + + try { + $result = json_decode($resultString, true, 512, JSON_THROW_ON_ERROR); + + return new DTO\Response( + new DTO\Result($result['result']), + new DTO\Time( + $result['time']['start'], + $result['time']['finish'], + $result['time']['duration'], + $result['time']['processing'], + new \DateTimeImmutable($result['time']['date_start']), + new \DateTimeImmutable($result['time']['date_finish']) + ) + ); + } catch (\JsonException $e) { + $this->logger->error($e->getMessage()); + } + } +} \ No newline at end of file From d89601a33ab52b7aa6a9afcad053f53339a849a0 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 31 Oct 2020 02:08:50 +0300 Subject: [PATCH 159/647] add time DTO --- README.md | 16 ++++-- docs/RU/Core/Auth/auth.md | 2 +- docs/RU/Core/Response/response.md | 10 ++++ docs/RU/documentation.md | 3 ++ .../DTO/{Response.php => ResponseData.php} | 4 +- src/Core/Response/DTO/Result.php | 2 +- src/Core/Response/DTO/Time.php | 23 +++++++++ src/Core/Response/Response.php | 16 ++---- src/Services/Main.php | 51 +++++++++++++++++++ tests/Unit/Core/Response/DTO/TimeTest.php | 40 +++++++++++++++ 10 files changed, 146 insertions(+), 21 deletions(-) create mode 100644 docs/RU/Core/Response/response.md rename src/Core/Response/DTO/{Response.php => ResponseData.php} (94%) create mode 100644 tests/Unit/Core/Response/DTO/TimeTest.php diff --git a/README.md b/README.md index d071353a..0d1c8eaa 100644 --- a/README.md +++ b/README.md @@ -5,12 +5,12 @@ bitrix24-php-sdk [![Build Status](https://travis-ci.org/mesilov/bitrix24-php-sdk A powerful PHP library for the Bitrix24 REST API [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) +[Bitrix24 API documentation - English](https://training.bitrix24.com/rest_help/)
+[Register new Bitrix24 account](https://www.bitrix24.ru/create.php?p=255670)
Bitrix24 auth features -- work with auth tokens +~~- work with auth tokens~~ - work with incoming webhooks add low-level tools to devs: @@ -23,10 +23,16 @@ API - level features - 3.2 offline queues - 3.3 add change domain URL support +Core DTO +- Response +- Scope +~~- Time~~ +- OAuthToken + + ## SDK Documentation - [Russian](/docs/RU/documentation.md) -- [English]() - +- [English](/docs/EN/documentation.md) ## Architecture diff --git a/docs/RU/Core/Auth/auth.md b/docs/RU/Core/Auth/auth.md index f4e4c287..f3ff0770 100644 --- a/docs/RU/Core/Auth/auth.md +++ b/docs/RU/Core/Auth/auth.md @@ -1,4 +1,4 @@ -Авторизация с использованием «Входящего вебхука» +# Авторизация с использованием «Входящего вебхука» ## Документация [Веб-хуки. Быстрый старт](https://dev.1c-bitrix.ru/learning/course/?COURSE_ID=99&LESSON_ID=8581) diff --git a/docs/RU/Core/Response/response.md b/docs/RU/Core/Response/response.md new file mode 100644 index 00000000..f9902d12 --- /dev/null +++ b/docs/RU/Core/Response/response.md @@ -0,0 +1,10 @@ +# Возвращаемый результат + +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/documentation.md b/docs/RU/documentation.md index cf8c4bec..5e132022 100644 --- a/docs/RU/documentation.md +++ b/docs/RU/documentation.md @@ -3,3 +3,6 @@ ## Авторизация на портале - с использованием [входящих веб-хуков](Core/Auth/auth.md) + +## Возвращаемые результаты +- diff --git a/src/Core/Response/DTO/Response.php b/src/Core/Response/DTO/ResponseData.php similarity index 94% rename from src/Core/Response/DTO/Response.php rename to src/Core/Response/DTO/ResponseData.php index 3afe2383..1931f190 100644 --- a/src/Core/Response/DTO/Response.php +++ b/src/Core/Response/DTO/ResponseData.php @@ -5,11 +5,11 @@ namespace Bitrix24\SDK\Core\Response\DTO; /** - * Class Response + * Class ResponseData * * @package Bitrix24\SDK\Core\Response\DTO */ -class Response +class ResponseData { /** * @var Result diff --git a/src/Core/Response/DTO/Result.php b/src/Core/Response/DTO/Result.php index 1a56e220..251a6ff0 100644 --- a/src/Core/Response/DTO/Result.php +++ b/src/Core/Response/DTO/Result.php @@ -29,7 +29,7 @@ public function __construct(array $result) /** * @return array */ - public function getResult(): array + public function getResultData(): array { return $this->result; } diff --git a/src/Core/Response/DTO/Time.php b/src/Core/Response/DTO/Time.php index 0db5501e..8bd32305 100644 --- a/src/Core/Response/DTO/Time.php +++ b/src/Core/Response/DTO/Time.php @@ -4,6 +4,11 @@ namespace Bitrix24\SDK\Core\Response\DTO; +/** + * Class Time + * + * @package Bitrix24\SDK\Core\Response\DTO + */ class Time { /** @@ -104,4 +109,22 @@ public function getDateFinish(): \DateTimeImmutable { return $this->dateFinish; } + + /** + * @param array $response + * + * @return static + * @throws \Exception + */ + public static function initFromResponse(array $response): self + { + return new self( + (float)$response['start'], + (float)$response['finish'], + (float)$response['duration'], + (float)$response['processing'], + new \DateTimeImmutable($response['date_start']), + new \DateTimeImmutable($response['date_finish']) + ); + } } \ No newline at end of file diff --git a/src/Core/Response/Response.php b/src/Core/Response/Response.php index c4107673..faed802f 100644 --- a/src/Core/Response/Response.php +++ b/src/Core/Response/Response.php @@ -45,29 +45,21 @@ public function getHttpResponse(): ResponseInterface } /** - * @return DTO\Response + * @return DTO\ResponseData * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface */ - public function getResponse(): DTO\Response + public function getResponseData(): DTO\ResponseData { $resultString = $this->httpResponse->getContent(); - try { $result = json_decode($resultString, true, 512, JSON_THROW_ON_ERROR); - return new DTO\Response( + return new DTO\ResponseData( new DTO\Result($result['result']), - new DTO\Time( - $result['time']['start'], - $result['time']['finish'], - $result['time']['duration'], - $result['time']['processing'], - new \DateTimeImmutable($result['time']['date_start']), - new \DateTimeImmutable($result['time']['date_finish']) - ) + DTO\Time::initFromResponse($result['time']) ); } catch (\JsonException $e) { $this->logger->error($e->getMessage()); diff --git a/src/Services/Main.php b/src/Services/Main.php index b3d9bbc7..6b2c05c6 100644 --- a/src/Services/Main.php +++ b/src/Services/Main.php @@ -1 +1,52 @@ apiClient = $apiClient; + $this->log = $log; + } + + /** + * @param string $apiMethod + * @param array $parameters + * + * @return Response + * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + */ + public function call(string $apiMethod, array $parameters = []): Response + { + $result = $this->apiClient->getResponse($apiMethod, $parameters); + + return new Response($result, $this->log); + } +} \ No newline at end of file diff --git a/tests/Unit/Core/Response/DTO/TimeTest.php b/tests/Unit/Core/Response/DTO/TimeTest.php new file mode 100644 index 00000000..46ef120b --- /dev/null +++ b/tests/Unit/Core/Response/DTO/TimeTest.php @@ -0,0 +1,40 @@ + 1604098405.469694, + 'finish' => 1604098405.50439, + 'duration' => 0.034696102142333984, + 'processing' => 6.198883056640625E-5, + 'date_start' => '2020-10-31T01:53:25+03:00', + 'date_finish' => '2020-10-31T01:53:26+03:00', + ]; + + $time = Time::initFromResponse($result); + + $this->assertEquals($result['start'], $time->getStart()); + $this->assertEquals($result['finish'], $time->getFinish()); + $this->assertEquals($result['duration'], $time->getDuration()); + $this->assertEquals($result['processing'], $time->getProcessing()); + $this->assertEquals($result['date_start'], $time->getDateStart()->format(\DATE_ATOM)); + $this->assertEquals($result['date_finish'], $time->getDateFinish()->format(\DATE_ATOM)); + } +} From 422d98bdbfb834f4daec0815dfa244b99eef5bd7 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 31 Oct 2020 15:14:10 +0300 Subject: [PATCH 160/647] update README.md --- README.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 0d1c8eaa..91af3c90 100644 --- a/README.md +++ b/README.md @@ -9,9 +9,11 @@ A powerful PHP library for the Bitrix24 REST API [Register new Bitrix24 account](https://www.bitrix24.ru/create.php?p=255670)
-Bitrix24 auth features -~~- work with auth tokens~~ -- work with incoming webhooks +## SDK 2.0 core features + +Bitrix24 auth features +- work with auth tokens +- ~~work with incoming webhooks~~ add low-level tools to devs: - 2.1 callbacks @@ -24,9 +26,9 @@ API - level features - 3.3 add change domain URL support Core DTO -- Response -- Scope -~~- Time~~ +- ~~Response~~ +- ~~Scope~~ +- ~~Time~~ - OAuthToken From 91b079738c623828e7dd73ecd0a38745dd540b1a Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 31 Oct 2020 23:30:00 +0300 Subject: [PATCH 161/647] add oauth support --- src/Core/ApiClient.php | 70 +++++++++++----- src/Core/Credentials/AccessToken.php | 86 ++++++++++++++++++++ src/Core/Credentials/ApplicationProfile.php | 64 +++++++++++++++ src/Core/Credentials/Credentials.php | 89 +++++++++++++++++---- src/Core/Credentials/OAuthToken.php | 55 ------------- src/Core/Response/Response.php | 25 +++++- src/Services/Main.php | 1 + 7 files changed, 298 insertions(+), 92 deletions(-) create mode 100644 src/Core/Credentials/AccessToken.php create mode 100644 src/Core/Credentials/ApplicationProfile.php delete mode 100644 src/Core/Credentials/OAuthToken.php diff --git a/src/Core/ApiClient.php b/src/Core/ApiClient.php index e8dbec1b..31c4f30c 100644 --- a/src/Core/ApiClient.php +++ b/src/Core/ApiClient.php @@ -4,7 +4,8 @@ namespace Bitrix24\SDK\Core; -use Bitrix24\SDK\Core\Credentials\OAuthToken; +use Bitrix24\SDK\Core\Credentials\AccessToken; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; use Psr\Log\LoggerInterface; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -29,6 +30,14 @@ class ApiClient * @var Credentials\Credentials */ protected $credentials; + /** + * @const string + */ + protected const BITRIX24_OAUTH_SERVER_URL = 'https://oauth.bitrix.info'; + /** + * @const string + */ + protected const SDK_VERSION = '2.0'; /** * ApiClient constructor. @@ -53,19 +62,42 @@ public function getCredentials(): Credentials\Credentials } /** - * @param Credentials\Credentials $credentials + * @return AccessToken + * @throws InvalidArgumentException + * @throws TransportExceptionInterface + * @throws \JsonException */ - public function setCredentials(Credentials\Credentials $credentials): void + public function getNewAccessToken(): AccessToken { - $this->credentials = $credentials; - } + $this->logger->debug(sprintf('getNewAccessToken.start')); + if ($this->getCredentials()->getApplicationProfile() === null) { + throw new InvalidArgumentException(sprintf('application profile not set')); + } + if ($this->getCredentials()->getAccessToken() === null) { + throw new InvalidArgumentException(sprintf('access token in credentials not set')); + } - /** - * @return OAuthToken - */ - public function getNewToken(): OAuthToken - { - return new OAuthToken('1', '2', 3600); + $method = 'GET'; + $url = sprintf( + '%s/oauth/token/?%s', + $this::BITRIX24_OAUTH_SERVER_URL, + http_build_query( + [ + 'grant_type' => 'refresh_token', + 'client_id' => $this->getCredentials()->getApplicationProfile()->getClientId(), + 'client_secret' => $this->getCredentials()->getApplicationProfile()->getClientSecret(), + 'refresh_token' => $this->getCredentials()->getAccessToken()->getRefreshToken(), + ] + ) + ); + + $response = $this->client->request($method, $url, []); + $result = $response->toArray(true); + $newAccessToken = AccessToken::initFromArray($result); + + $this->logger->debug(sprintf('getNewAccessToken.finish')); + + return $newAccessToken; } /** @@ -74,6 +106,7 @@ public function getNewToken(): OAuthToken * * @return ResponseInterface * @throws TransportExceptionInterface + * @throws InvalidArgumentException */ public function getResponse(string $apiMethod, array $parameters = []): ResponseInterface { @@ -86,19 +119,20 @@ public function getResponse(string $apiMethod, array $parameters = []): Response ); $method = 'POST'; - - if ($this->credentials->getWebhookUrl() !== null) { - $url = sprintf('%s/%s/', $this->credentials->getWebhookUrl()->getUrl(), $apiMethod); + if ($this->getCredentials()->getWebhookUrl() !== null) { + $url = sprintf('%s/%s/', $this->getCredentials()->getWebhookUrl()->getUrl(), $apiMethod); } else { - // todo domain rename case - $url = sprintf('%s/%s', $this->credentials->getDomainUrl(), $apiMethod); - } + $url = sprintf('%s/rest/%s', $this->getCredentials()->getDomainUrl(), $apiMethod); + if ($this->getCredentials()->getAccessToken() === null) { + throw new InvalidArgumentException(sprintf('access token in credentials not found ')); + } + $parameters['auth'] = $this->getCredentials()->getAccessToken()->getAccessToken(); + } $requestOptions = [ 'json' => $parameters, ]; - $response = $this->client->request($method, $url, $requestOptions); $this->logger->debug( diff --git a/src/Core/Credentials/AccessToken.php b/src/Core/Credentials/AccessToken.php new file mode 100644 index 00000000..6600bcda --- /dev/null +++ b/src/Core/Credentials/AccessToken.php @@ -0,0 +1,86 @@ +accessToken = $accessToken; + $this->refreshToken = $refreshToken; + $this->expires = $expires; + } + + /** + * @return string + */ + public function getAccessToken(): string + { + return $this->accessToken; + } + + /** + * @return string + */ + 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 static + */ + public static function initFromArray(array $request): self + { + return new self( + (string)$request['access_token'], + (string)$request['refresh_token'], + (int)$request['expires'] + ); + } +} \ No newline at end of file diff --git a/src/Core/Credentials/ApplicationProfile.php b/src/Core/Credentials/ApplicationProfile.php new file mode 100644 index 00000000..ea5f1f6e --- /dev/null +++ b/src/Core/Credentials/ApplicationProfile.php @@ -0,0 +1,64 @@ +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; + } +} \ No newline at end of file diff --git a/src/Core/Credentials/Credentials.php b/src/Core/Credentials/Credentials.php index 714c62ef..4d367dad 100644 --- a/src/Core/Credentials/Credentials.php +++ b/src/Core/Credentials/Credentials.php @@ -16,9 +16,14 @@ class Credentials */ protected $webhookUrl; /** - * @var OAuthToken|null + * @var AccessToken|null */ - protected $oauthToken; + protected $accessToken; + /** + * @var ApplicationProfile|null + */ + protected $applicationProfile; + /** * @var string|null */ @@ -27,23 +32,45 @@ class Credentials /** * Credentials constructor. * - * @param WebhookUrl|null $webhookUrl - * @param OAuthToken|null $oauthToken - * @param string|null $domainUrl + * @param WebhookUrl|null $webhookUrl + * @param AccessToken|null $accessToken + * @param ApplicationProfile|null $applicationProfile + * @param string|null $domainUrl */ - public function __construct(?WebhookUrl $webhookUrl, ?OAuthToken $oauthToken, ?string $domainUrl) - { + public function __construct( + ?WebhookUrl $webhookUrl, + ?AccessToken $accessToken, + ?ApplicationProfile $applicationProfile, + ?string $domainUrl + ) { $this->webhookUrl = $webhookUrl; - $this->oauthToken = $oauthToken; + $this->accessToken = $accessToken; + $this->applicationProfile = $applicationProfile; $this->domainUrl = $domainUrl; - if ($this->oauthToken === null && $this->webhookUrl === null) { - throw new \LogicException(sprintf('you must set on of auth type: webhook or oauth')); + if ($this->accessToken === null && $this->webhookUrl === null) { + throw new \LogicException(sprintf('you must set on of auth type: webhook or OAuth 2.0')); } - if ($this->oauthToken !== null && $this->domainUrl === null) { + if ($this->accessToken !== null && $this->domainUrl === null) { throw new \LogicException(sprintf('for oauth type you must set domain url')); } } + /** + * @param AccessToken $accessToken + */ + public function setAccessToken(AccessToken $accessToken): void + { + $this->accessToken = $accessToken; + } + + /** + * @return ApplicationProfile|null + */ + public function getApplicationProfile(): ?ApplicationProfile + { + return $this->applicationProfile; + } + /** * @return string */ @@ -52,7 +79,7 @@ public function getDomainUrl(): string if ($this->getWebhookUrl() !== null) { $url = parse_url($this->getWebhookUrl()->getUrl())['host']; } else { - $url = $this->getDomainUrl(); + $url = $this->domainUrl; } return $url; @@ -67,10 +94,42 @@ public function getWebhookUrl(): ?WebhookUrl } /** - * @return OAuthToken|null + * @return AccessToken|null + */ + public function getAccessToken(): ?AccessToken + { + return $this->accessToken; + } + + /** + * @param WebhookUrl $webhookUrl + * + * @return static + */ + public static function createForWebHook(WebhookUrl $webhookUrl): self + { + return new self( + $webhookUrl, + null, + null, + null + ); + } + + /** + * @param AccessToken $accessToken + * @param ApplicationProfile $applicationProfile + * @param string $domainUrl + * + * @return static */ - public function getOauthToken(): ?OAuthToken + public static function createForOAuth(AccessToken $accessToken, ApplicationProfile $applicationProfile, string $domainUrl): self { - return $this->oauthToken; + return new self( + null, + $accessToken, + $applicationProfile, + $domainUrl + ); } } \ No newline at end of file diff --git a/src/Core/Credentials/OAuthToken.php b/src/Core/Credentials/OAuthToken.php deleted file mode 100644 index 2a745a6d..00000000 --- a/src/Core/Credentials/OAuthToken.php +++ /dev/null @@ -1,55 +0,0 @@ -authToken = $authToken; - $this->refreshToken = $refreshToken; - $this->expiresIn = $expiresIn; - } - - /** - * @return string - */ - public function getAuthToken(): string - { - return $this->authToken; - } - - /** - * @return string - */ - public function getRefreshToken(): string - { - return $this->refreshToken; - } - - /** - * @return int - */ - public function getExpiresIn(): int - { - return $this->expiresIn; - } -} \ No newline at end of file diff --git a/src/Core/Response/Response.php b/src/Core/Response/Response.php index faed802f..7e6763c4 100644 --- a/src/Core/Response/Response.php +++ b/src/Core/Response/Response.php @@ -53,16 +53,33 @@ public function getHttpResponse(): ResponseInterface */ public function getResponseData(): DTO\ResponseData { + $this->logger->debug('getResponseData.start'); $resultString = $this->httpResponse->getContent(); try { - $result = json_decode($resultString, true, 512, JSON_THROW_ON_ERROR); + $responseResult = json_decode($resultString, true, 512, JSON_THROW_ON_ERROR); + + $resultDto = new DTO\Result($responseResult['result']); + $time = DTO\Time::initFromResponse($responseResult['time']); + + $this->logger->debug( + 'getResponseData.finish', + [ + 'result' => $resultDto->getResultData(), + 'durationTime' => $time->getDuration(), + ] + ); return new DTO\ResponseData( - new DTO\Result($result['result']), - DTO\Time::initFromResponse($result['time']) + $resultDto, + $time ); } catch (\JsonException $e) { - $this->logger->error($e->getMessage()); + $this->logger->error( + $e->getMessage(), + [ + 'response' => $this->httpResponse->getContent(), + ] + ); } } } \ No newline at end of file diff --git a/src/Services/Main.php b/src/Services/Main.php index 6b2c05c6..ea469924 100644 --- a/src/Services/Main.php +++ b/src/Services/Main.php @@ -42,6 +42,7 @@ public function __construct(ApiClient $apiClient, LoggerInterface $log) * * @return Response * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException */ public function call(string $apiMethod, array $parameters = []): Response { From 569d05cdc93832bad11f4ba8c36dee9dac6733ad Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 31 Oct 2020 23:35:20 +0300 Subject: [PATCH 162/647] add docs --- CHANGELOG.md | 2 ++ README.md | 8 +++---- docs/RU/Core/Auth/auth.md | 45 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 350ce915..6c654637 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,9 @@ # bitrix24-php-sdk change log ## 2.0 DEV * remove all old code +* migrate to Symfony HttpClient * add documentation webhook auth type +* add OAuth 2.0 support ## 0.7.0 (11.07.2020) * add arguments in method `Bitrix24\Bizproc\Robot::add` for return results support diff --git a/README.md b/README.md index 91af3c90..4e3d93fc 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,11 @@ A powerful PHP library for the Bitrix24 REST API ## SDK 2.0 core features Bitrix24 auth features -- work with auth tokens +- ~~work with auth tokens~~ - ~~work with incoming webhooks~~ add low-level tools to devs: -- 2.1 callbacks +- 2.1 callbacks (token expired, domain url changed) - 2.2 rate-limiter - wait for symfony/symfony#37471 - 2.3 RetryHttpClient - symfony/symfony#38182 @@ -29,8 +29,8 @@ Core DTO - ~~Response~~ - ~~Scope~~ - ~~Time~~ -- OAuthToken - +- ~~OAuthToken~~ +- ~~ApplicationProfile~~ ## SDK Documentation - [Russian](/docs/RU/documentation.md) diff --git a/docs/RU/Core/Auth/auth.md b/docs/RU/Core/Auth/auth.md index f3ff0770..a8a0896f 100644 --- a/docs/RU/Core/Auth/auth.md +++ b/docs/RU/Core/Auth/auth.md @@ -26,6 +26,7 @@ $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 ); @@ -36,3 +37,47 @@ $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://loyalty-dev-2020-10.bitrix24.ru'; +$credentials = \Bitrix24\SDK\Core\Credentials\Credentials::createForOAuth($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 From f8cb3c2d2bdaae0f0d391ccdd066b4cd842c7695 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 31 Oct 2020 23:44:48 +0300 Subject: [PATCH 163/647] add docs fix --- docs/RU/Core/Auth/auth.md | 3 +-- docs/RU/documentation.md | 5 +++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/RU/Core/Auth/auth.md b/docs/RU/Core/Auth/auth.md index a8a0896f..2e0364f5 100644 --- a/docs/RU/Core/Auth/auth.md +++ b/docs/RU/Core/Auth/auth.md @@ -70,13 +70,12 @@ $token = new \Bitrix24\SDK\Core\Credentials\AccessToken( '404bc55… refresh token', 1604179882 ); -$domain = 'https://loyalty-dev-2020-10.bitrix24.ru'; +$domain = 'https:// client portal address .bitrix24.ru'; $credentials = \Bitrix24\SDK\Core\Credentials\Credentials::createForOAuth($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()); diff --git a/docs/RU/documentation.md b/docs/RU/documentation.md index 5e132022..37903c59 100644 --- a/docs/RU/documentation.md +++ b/docs/RU/documentation.md @@ -3,6 +3,7 @@ ## Авторизация на портале - с использованием [входящих веб-хуков](Core/Auth/auth.md) +- с использованием [OAuth 2.0 токенов](Core/Auth/auth.md#подключение-к-битрикс24-с-использованием-oauth-20) -## Возвращаемые результаты -- +## Возвращаемые результаты ApiClient +- унифицированный объект [Response](Core/Response/response.md) From 78475ddd627b0fe560708f778da8dc54bf46eccd Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 7 Nov 2020 19:59:14 +0300 Subject: [PATCH 164/647] add renew access token support --- CHANGELOG.md | 1 + README.md | 14 +- composer.json | 4 +- docs/RU/Core/Events/events.md | 8 + docs/RU/documentation.md | 5 + examples/core/oauth-examp.php | 61 +++++++ src/Core/ApiClient.php | 10 +- src/Core/Credentials/Scope.php | 1 + src/Core/Response/DTO/RenewedAccessToken.php | 161 +++++++++++++++++++ src/Core/Response/Response.php | 99 +++++++++--- src/Events/AuthTokenRenewedEvent.php | 39 +++++ src/Services/Main.php | 80 ++++++++- 12 files changed, 439 insertions(+), 44 deletions(-) create mode 100644 docs/RU/Core/Events/events.md create mode 100644 examples/core/oauth-examp.php create mode 100644 src/Core/Response/DTO/RenewedAccessToken.php create mode 100644 src/Events/AuthTokenRenewedEvent.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c654637..700963d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * migrate to Symfony HttpClient * add documentation webhook auth type * add OAuth 2.0 support +* add Events support ## 0.7.0 (11.07.2020) * add arguments in method `Bitrix24\Bizproc\Robot::add` for return results support diff --git a/README.md b/README.md index 4e3d93fc..d67dd9c1 100644 --- a/README.md +++ b/README.md @@ -16,14 +16,15 @@ Bitrix24 auth features - ~~work with incoming webhooks~~ add low-level tools to devs: -- 2.1 callbacks (token expired, domain url changed) +- ~~2.1 events (token expired, domain url changed)~~ - 2.2 rate-limiter - wait for symfony/symfony#37471 - 2.3 RetryHttpClient - symfony/symfony#38182 API - level features -- 3.1 batch queries -- 3.2 offline queues -- 3.3 add change domain URL support +- ~~3.1 auto renew access tokens~~ +- 3.2 batch queries +- 3.3 offline queues +- 3.4 add change domain URL support Core DTO - ~~Response~~ @@ -53,9 +54,6 @@ Core DTO process: b24 entities, operate with ``` - - - ### File Structure ``` /Core @@ -78,7 +76,7 @@ Core DTO ## Example ## ## Installation ## -Add `"mesilov/bitrix24-php-sdk": "dev-master"` to `composer.json` of your application. Or clone repo to your project. +Add `"mesilov/bitrix24-php-sdk": "2.x"` to `composer.json` of your application. Or clone repo to your project. ## Submitting bugs and feature requests diff --git a/composer.json b/composer.json index 3563cc45..d829bebf 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,9 @@ "ext-json": "*", "ext-curl": "*", "psr/log": "1.1.3", - "symfony/http-client": "5.1.*" + "fig/http-message-util": "1.1.*", + "symfony/http-client": "5.1.*", + "symfony/event-dispatcher": "5.1.*" }, "require-dev": { "phpunit/phpunit": "9.3.*", diff --git a/docs/RU/Core/Events/events.md b/docs/RU/Core/Events/events.md new file mode 100644 index 00000000..d4dbc56c --- /dev/null +++ b/docs/RU/Core/Events/events.md @@ -0,0 +1,8 @@ +# Events +SDK может уведомить клиентский код о наступлении событий связанных с жизненным циклом приложения. + +## Событие «AUTH_TOKEN_RENEWED» — обновлён токен авторизации +Выбрасывается после того, как библиотека сама обновила авторизационный токен и выполнила с ним первый удачный запрос. +Подписавшись на это событие у вас будет возможность сохранить новую пару: +- accessToken +- refreshToken \ No newline at end of file diff --git a/docs/RU/documentation.md b/docs/RU/documentation.md index 37903c59..fb7e8616 100644 --- a/docs/RU/documentation.md +++ b/docs/RU/documentation.md @@ -7,3 +7,8 @@ ## Возвращаемые результаты ApiClient - унифицированный объект [Response](Core/Response/response.md) + +## Обработка событий +При работе с SDK могут возникать события, которые требуется обработать в клиентском коде. +Библиотека позволяет подписаться на эти события с помощью компонента `EventDispatcher` +Список [событий](Core/Events/events.md), на которые можно подписаться. \ No newline at end of file diff --git a/examples/core/oauth-examp.php b/examples/core/oauth-examp.php new file mode 100644 index 00000000..4f2225e1 --- /dev/null +++ b/examples/core/oauth-examp.php @@ -0,0 +1,61 @@ +pushHandler(new StreamHandler('b24-api-client-debug.log', Logger::DEBUG)); + +$client = HttpClient::create(['http_version' => '2.0']); +$traceableClient = new \Symfony\Component\HttpClient\TraceableHttpClient($client); +$traceableClient->setLogger($log); + +$appProfile = new \Bitrix24\SDK\Core\Credentials\ApplicationProfile( + 'local.5f9d4c50b2bf08.70341243', + 'YE56q7neK8SJgP8xqDBlTP2oPYSUf7HUySkob0w9wOWFr1XZCv', + new \Bitrix24\SDK\Core\Credentials\Scope( + [ + 'crm', + ] + ) +); +$token = new \Bitrix24\SDK\Core\Credentials\AccessToken( + '50cc… access token', + '404b… refresh token', + 0 +); +$domain = 'https://domain.bitrix24.ru'; +$credentials = \Bitrix24\SDK\Core\Credentials\Credentials::createForOAuth($token, $appProfile, $domain); + +try { + $apiClient = new \Bitrix24\SDK\Core\ApiClient($credentials, $traceableClient, $log); + + $ed = new \Symfony\Component\EventDispatcher\EventDispatcher(); + $ed->addListener( + \Bitrix24\SDK\Events\AuthTokenRenewedEvent::class, + static function (\Bitrix24\SDK\Events\AuthTokenRenewedEvent $event) { + var_dump('AuthTokenRenewed!'); + print($event->getRenewedToken()->getAccessToken()->getAccessToken() . PHP_EOL); + } + ); + + $app = new \Bitrix24\SDK\Services\Main($apiClient, $ed, $log); + + $log->debug('================================'); + + // api call with expired access token + $res = $app->call('app.info'); + print('result:' . PHP_EOL); + + var_dump($res->getResponseData()->getResult()->getResultData()); + var_dump($res->getResponseData()->getTime()->getDuration()); +} catch (\Throwable $exception) { + print(sprintf('error: %s', $exception->getMessage()) . PHP_EOL); + print(sprintf('class: %s', get_class($exception)) . PHP_EOL); + print(sprintf('trace: %s', $exception->getTraceAsString()) . PHP_EOL); +} \ No newline at end of file diff --git a/src/Core/ApiClient.php b/src/Core/ApiClient.php index 31c4f30c..f0a09ab5 100644 --- a/src/Core/ApiClient.php +++ b/src/Core/ApiClient.php @@ -4,8 +4,8 @@ namespace Bitrix24\SDK\Core; -use Bitrix24\SDK\Core\Credentials\AccessToken; use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Response\DTO\RenewedAccessToken; use Psr\Log\LoggerInterface; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -62,12 +62,12 @@ public function getCredentials(): Credentials\Credentials } /** - * @return AccessToken + * @return RenewedAccessToken * @throws InvalidArgumentException * @throws TransportExceptionInterface * @throws \JsonException */ - public function getNewAccessToken(): AccessToken + public function getNewAccessToken(): RenewedAccessToken { $this->logger->debug(sprintf('getNewAccessToken.start')); if ($this->getCredentials()->getApplicationProfile() === null) { @@ -92,8 +92,8 @@ public function getNewAccessToken(): AccessToken ); $response = $this->client->request($method, $url, []); - $result = $response->toArray(true); - $newAccessToken = AccessToken::initFromArray($result); + $result = $response->toArray(false); + $newAccessToken = RenewedAccessToken::initFromArray($result); $this->logger->debug(sprintf('getNewAccessToken.finish')); diff --git a/src/Core/Credentials/Scope.php b/src/Core/Credentials/Scope.php index 9962ea06..a7375659 100644 --- a/src/Core/Credentials/Scope.php +++ b/src/Core/Credentials/Scope.php @@ -17,6 +17,7 @@ class Scope * @var string[] */ protected $availableScope = [ + 'app', 'bizproc', 'calendar', 'call', diff --git a/src/Core/Response/DTO/RenewedAccessToken.php b/src/Core/Response/DTO/RenewedAccessToken.php new file mode 100644 index 00000000..6623fd2e --- /dev/null +++ b/src/Core/Response/DTO/RenewedAccessToken.php @@ -0,0 +1,161 @@ +accessToken = $accessToken; + $this->scope = $scope; + $this->memberId = $memberId; + $this->clientEndpoint = $clientEndpoint; + $this->serverEndpoint = $serverEndpoint; + $this->applicationStatus = $applicationStatus; + $this->domain = $domain; + } + + /** + * @return AccessToken + */ + public function getAccessToken(): AccessToken + { + return $this->accessToken; + } + + /** + * @return Scope + */ + public function getScope(): Scope + { + return $this->scope; + } + + /** + * @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 static + * @throws \Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException + */ + public static function initFromArray(array $response): self + { + return new self( + AccessToken::initFromArray($response), + new Scope(explode(',', (string)$response['scope'])), + (string)$response['member_id'], + (string)$response['client_endpoint'], + (string)$response['server_endpoint'], + (string)$response['status'], + (string)$response['domain'] + ); + } +} + +//{ +// "access_token": "s1morf609228iwyjjpvfv6wsvuja4p8u", +// "refresh_token": "4f9k4jpmg13usmybzuqknt2v9fh0q6rl", +// "expires_in": 3600, +// "scope": "app", +// "member_id": "a223c6b3710f85df22e9377d6c4f7553", +// "client_endpoint": "https://portal.bitrix24.com/rest/", +// "server_endpoint": "https://oauth.bitrix.info/rest/", +// "domain": "oauth.bitrix.info", +// "status": "T" +//} \ No newline at end of file diff --git a/src/Core/Response/Response.php b/src/Core/Response/Response.php index 7e6763c4..8c60acc0 100644 --- a/src/Core/Response/Response.php +++ b/src/Core/Response/Response.php @@ -4,6 +4,7 @@ namespace Bitrix24\SDK\Core\Response; +use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Response\DTO; use Psr\Log\LoggerInterface; use Symfony\Contracts\HttpClient\ResponseInterface; @@ -23,6 +24,10 @@ class Response * @var LoggerInterface */ protected $logger; + /** + * @var DTO\ResponseData|null + */ + protected $responseData; /** * Response constructor. @@ -46,6 +51,7 @@ public function getHttpResponse(): ResponseInterface /** * @return DTO\ResponseData + * @throws BaseException * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface @@ -54,32 +60,77 @@ public function getHttpResponse(): ResponseInterface public function getResponseData(): DTO\ResponseData { $this->logger->debug('getResponseData.start'); - $resultString = $this->httpResponse->getContent(); - try { - $responseResult = json_decode($resultString, true, 512, JSON_THROW_ON_ERROR); - - $resultDto = new DTO\Result($responseResult['result']); - $time = DTO\Time::initFromResponse($responseResult['time']); - - $this->logger->debug( - 'getResponseData.finish', - [ - 'result' => $resultDto->getResultData(), - 'durationTime' => $time->getDuration(), - ] - ); - return new DTO\ResponseData( - $resultDto, - $time - ); - } catch (\JsonException $e) { - $this->logger->error( - $e->getMessage(), - [ - 'response' => $this->httpResponse->getContent(), - ] + if ($this->responseData === null) { + try { + $responseResult = $this->httpResponse->toArray(true); + + $this->handleApiLevelErrors($responseResult); + + $resultDto = new DTO\Result($responseResult['result']); + $time = DTO\Time::initFromResponse($responseResult['time']); + $this->responseData = new DTO\ResponseData( + $resultDto, + $time + ); + } catch (\Throwable $e) { + $this->logger->error( + $e->getMessage(), + [ + 'response' => $this->httpResponse->getContent(false), + ] + ); + throw new BaseException(sprintf('api request error: %s', $e->getMessage()), $e->getCode(), $e); + } + } + $this->logger->debug('getResponseData.finish'); + + return $this->responseData; + } + + + /** + * @param array $apiResponse + */ + private function handleApiLevelErrors(array $apiResponse): void + { + $this->logger->debug('handleApiLevelErrors.start'); + + if (array_key_exists('error', $apiResponse)) { + $errorMsg = sprintf( + '%s - %s ', + $apiResponse['error'], + (array_key_exists('error_description', $apiResponse) ? $apiResponse['error_description'] : ''), ); + +// switch (strtoupper(trim($apiResponse['error']))) { +// case 'EXPIRED_TOKEN': +// throw new Bitrix24TokenIsExpiredException($errorMsg); +// case 'WRONG_CLIENT': +// case 'ERROR_OAUTH': +// $this->log->error($errorMsg, $this->getErrorContext()); +// throw new Bitrix24WrongClientException($errorMsg); +// case 'ERROR_METHOD_NOT_FOUND': +// $this->log->error($errorMsg, $this->getErrorContext()); +// throw new Bitrix24MethodNotFoundException($errorMsg); +// case 'INVALID_TOKEN': +// case 'INVALID_GRANT': +// $this->log->error($errorMsg, $this->getErrorContext()); +// throw new Bitrix24TokenIsInvalidException($errorMsg); + +// case 'PAYMENT_REQUIRED': +// $this->log->error($errorMsg, $this->getErrorContext()); +// throw new Bitrix24PaymentRequiredException($errorMsg); +// case 'NO_AUTH_FOUND': +// $this->log->error($errorMsg, $this->getErrorContext()); +// throw new Bitrix24PortalRenamedException($errorMsg); +// case 'INSUFFICIENT_SCOPE': +// $this->log->error($errorMsg, $this->getErrorContext()); +// throw new Bitrix24InsufficientScope($errorMsg); +// default: +// $this->log->error($errorMsg, $this->getErrorContext()); +// throw new Bitrix24ApiException($errorMsg); } + $this->logger->debug('handleApiLevelErrors.finish'); } } \ No newline at end of file diff --git a/src/Events/AuthTokenRenewedEvent.php b/src/Events/AuthTokenRenewedEvent.php new file mode 100644 index 00000000..96a6f1b1 --- /dev/null +++ b/src/Events/AuthTokenRenewedEvent.php @@ -0,0 +1,39 @@ +renewedToken = $renewedToken; + } + + /** + * @return RenewedAccessToken + */ + public function getRenewedToken(): RenewedAccessToken + { + return $this->renewedToken; + } +} diff --git a/src/Services/Main.php b/src/Services/Main.php index ea469924..30f001d3 100644 --- a/src/Services/Main.php +++ b/src/Services/Main.php @@ -5,8 +5,12 @@ namespace Bitrix24\SDK\Services; use Bitrix24\SDK\Core\ApiClient; +use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Response\Response; +use Bitrix24\SDK\Events\AuthTokenRenewedEvent; +use Fig\Http\Message\StatusCodeInterface; use Psr\Log\LoggerInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * Class Main @@ -23,16 +27,22 @@ class Main * @var LoggerInterface */ protected $log; + /** + * @var EventDispatcherInterface + */ + protected $eventDispatcher; /** * Main constructor. * - * @param ApiClient $apiClient - * @param LoggerInterface $log + * @param ApiClient $apiClient + * @param EventDispatcherInterface $eventDispatcher + * @param LoggerInterface $log */ - public function __construct(ApiClient $apiClient, LoggerInterface $log) + public function __construct(ApiClient $apiClient, EventDispatcherInterface $eventDispatcher, LoggerInterface $log) { $this->apiClient = $apiClient; + $this->eventDispatcher = $eventDispatcher; $this->log = $log; } @@ -41,13 +51,71 @@ public function __construct(ApiClient $apiClient, LoggerInterface $log) * @param array $parameters * * @return Response - * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + * @throws \JsonException + * @throws BaseException */ public function call(string $apiMethod, array $parameters = []): Response { - $result = $this->apiClient->getResponse($apiMethod, $parameters); + $this->log->debug( + 'call.start', + [ + 'method' => $apiMethod, + 'parameters' => $parameters, + ] + ); + + // make async request + $apiCallResult = $this->apiClient->getResponse($apiMethod, $parameters); + + $response = null; + switch ($apiCallResult->getStatusCode()) { + case StatusCodeInterface::STATUS_OK: + //todo check with empty response size from server + $response = new Response($apiCallResult, $this->log); + break; + case StatusCodeInterface::STATUS_UNAUTHORIZED: + $body = $apiCallResult->toArray(false); + $this->log->notice( + 'UNAUTHORIZED request', + [ + 'body' => $body, + ] + ); + + if ($body['error'] === 'expired_token') { + // renew access token + $renewedToken = $this->apiClient->getNewAccessToken(); + $this->log->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->log->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'); + } + } + $this->log->debug('call.finish'); - return new Response($result, $this->log); + return $response; } } \ No newline at end of file From a938c737f32e74eaa15ac115b9c88d63394f0edb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B5=D0=BD=D0=B8=D1=81?= Date: Fri, 20 Nov 2020 22:35:14 +0500 Subject: [PATCH 165/647] Add getById method to User class --- src/classes/user/user.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/classes/user/user.php b/src/classes/user/user.php index 83ed2d8e..6b8fce0a 100644 --- a/src/classes/user/user.php +++ b/src/classes/user/user.php @@ -41,6 +41,22 @@ public function fields() return $result; } + /** + * Get user by id + * @link http://dev.1c-bitrix.ru/rest_help/users/user_get.php + * @throws Bitrix24Exception + * @param $id - user id + * @return array + */ + public function getById($id) { + $result = $this->client->call('user.get', + array( + 'ID' => $id, + ) + ); + return $result; + } + /** * Get list of users * @link http://dev.1c-bitrix.ru/rest_help/users/user_get.php From c1c71648faff617f31d27cf3f83cdf99755e662a Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 29 Nov 2020 14:22:33 +0300 Subject: [PATCH 166/647] add batch query service for write model --- README.md | 6 + composer.json | 3 +- .../core/batch-query-iterable-write-examp.php | 101 ++++++++++ src/Core/Batch.php | 174 ++++++++++++++++++ src/Core/Commands/Command.php | 82 +++++++++ src/Core/Commands/CommandCollection.php | 19 ++ src/Core/Core.php | 120 ++++++++++++ .../Response/DTO/ResponseDataCollection.php | 18 ++ src/Core/Response/Response.php | 6 +- src/Services/AbstractService.php | 37 ++++ src/Services/CRM/Deals/Service/Deals.php | 55 ++++++ src/Services/Main.php | 120 +++--------- 12 files changed, 640 insertions(+), 101 deletions(-) create mode 100644 examples/core/batch-query-iterable-write-examp.php create mode 100644 src/Core/Batch.php create mode 100644 src/Core/Commands/Command.php create mode 100644 src/Core/Commands/CommandCollection.php create mode 100644 src/Core/Core.php create mode 100644 src/Core/Response/DTO/ResponseDataCollection.php create mode 100644 src/Services/AbstractService.php create mode 100644 src/Services/CRM/Deals/Service/Deals.php diff --git a/README.md b/README.md index d67dd9c1..42d2fd94 100644 --- a/README.md +++ b/README.md @@ -93,3 +93,9 @@ See also the list of [contributors](https://github.com/mesilov/bitrix24-php-sdk/ ## Need custom Bitrix24 application? ## email: + + +## Русский + +### Ключевые особенности +- сервисы возвращают структуры данных пригодные для работы внутри клиентского кода \ No newline at end of file diff --git a/composer.json b/composer.json index d829bebf..24263d4d 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,8 @@ "psr/log": "1.1.3", "fig/http-message-util": "1.1.*", "symfony/http-client": "5.1.*", - "symfony/event-dispatcher": "5.1.*" + "symfony/event-dispatcher": "5.1.*", + "ramsey/uuid": "^3.9.3" }, "require-dev": { "phpunit/phpunit": "9.3.*", diff --git a/examples/core/batch-query-iterable-write-examp.php b/examples/core/batch-query-iterable-write-examp.php new file mode 100644 index 00000000..932a1a44 --- /dev/null +++ b/examples/core/batch-query-iterable-write-examp.php @@ -0,0 +1,101 @@ +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); + +$credentials = Bitrix24\SDK\Core\Credentials\Credentials::createForWebHook( + new \Bitrix24\SDK\Core\Credentials\WebhookUrl('https://') +); + +try { + $apiClient = new \Bitrix24\SDK\Core\ApiClient($credentials, $traceableClient, $log); + $ed = new \Symfony\Component\EventDispatcher\EventDispatcher(); + $core = new \Bitrix24\SDK\Core\Core($apiClient, $ed, $log); + + $arraySize = 120; + print(sprintf('Prepare raw data example...') . PHP_EOL); + $rawDeals = []; + for ($i = 0; $i < $arraySize; $i++) { + $rawDeals[] = [ + 'TITLE' => sprintf('deal-%s', $i), + 'OPPORTUNITY' => 500, + 'CONTACT_ID' => 76, + ]; + } + print(sprintf('deals data count: %s', count($rawDeals)) . PHP_EOL); + print(sprintf('--------') . PHP_EOL); + + + // собираем операции добавления сделок в батч-запросы + $batch = new \Bitrix24\SDK\Core\Batch($core, $log); + foreach ($rawDeals as $cnt => $deal) { + $batch->addCommand('crm.deal.add', $deal); + } + print(sprintf('batch commands registered') . PHP_EOL); + + + // получаем данные батч-запросов + print(sprintf('call batch queries and get traversable results for each command...') . PHP_EOL); + + + // iterate api-calls result + $timeStart = microtime(true); + foreach ($batch->getTraversable(true) as $queryCnt => $queryResultData) { + /** + * @var $queryResultData \Bitrix24\SDK\Core\Response\DTO\ResponseData + */ + + print(sprintf(' single query number %s: ', $queryCnt) . PHP_EOL); + print(sprintf( + ' time |start: %s |duration %s |', + $queryResultData->getTime()->getDateStart()->format('H:i:s'), + $queryResultData->getTime()->getDuration(), + ) . PHP_EOL); + + print(sprintf(' deal id: %s', $queryResultData->getResult()->getResultData()[0]) . PHP_EOL); + + print(sprintf(' --') . PHP_EOL); + } + $timeEnd = microtime(true); + print(sprintf('batch query duration: %s seconds', round($timeEnd - $timeStart, 2)) . PHP_EOL . PHP_EOL); + // todo режим добавление с чтением + + +// сравниваем с последовательным добавлением сделок +// print(sprintf('compare with single query mode...') . PHP_EOL); +// $dealsService = new \Bitrix24\SDK\Services\CRM\Deals\Service\Deals($core, $log); +// $timeStart = microtime(true); +// foreach ($rawDeals as $cnt => $deal) { +// $dealId = $dealsService->add($deal); +// print(sprintf('%s | deal id - %s', $cnt, $dealId) . PHP_EOL); +// } +// $timeEnd = microtime(true); +// print(sprintf(' single query mode time: %s', $timeEnd - $timeStart) . PHP_EOL); + +} catch (\Throwable $exception) { + print(sprintf('ошибка: %s', $exception->getMessage()) . PHP_EOL); + print(sprintf('тип: %s', get_class($exception)) . PHP_EOL); + print(sprintf('trace: %s', $exception->getTraceAsString()) . PHP_EOL); +} + + + + + + + + + + diff --git a/src/Core/Batch.php b/src/Core/Batch.php new file mode 100644 index 00000000..013e11d2 --- /dev/null +++ b/src/Core/Batch.php @@ -0,0 +1,174 @@ +coreService = $core; + $this->log = $log; + $this->commands = new CommandCollection(); + } + + /** + * Clear api commands collection + */ + public function clearCommands(): void + { + $this->commands = new CommandCollection(); + } + + /** + * add api command to commands collection for batch calls + * + * @param string $apiMethod + * @param array $parameters + * @param string|null $commandName + * @param callable|null $callback + * + * @throws \Exception + */ + public function addCommand( + string $apiMethod, + array $parameters = [], + ?string $commandName = null, + callable $callback = null + ) { + $this->commands->attach(new Command($apiMethod, $parameters, $commandName)); + } + + /** + * @param bool $isHaltOnError + * + * @return Response + * @throws BaseException + * @throws Exceptions\InvalidArgumentException + * @throws \JsonException + * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + */ + public function getTraversable(bool $isHaltOnError): Traversable + { + foreach ($this->getTraversableBatchResults($isHaltOnError) as $batchItem => $batchResult) { + /** + * @var $batchResult Response + */ + $response = $batchResult->getResponseData(); + + $resultDataItems = $response->getResult()->getResultData()['result']; + $resultQueryTimeItems = $response->getResult()->getResultData()['result_time']; + foreach ($resultDataItems as $singleQueryKey => $singleQueryResult) { + if (!is_array($singleQueryResult)) { + $singleQueryResult = [$singleQueryResult]; + } + if (!array_key_exists($singleQueryKey, $resultQueryTimeItems)) { + throw new BaseException(sprintf('query time with key %s not found', $singleQueryKey)); + } + + yield new ResponseData(new Result($singleQueryResult), Time::initFromResponse($resultQueryTimeItems[$singleQueryKey])); + } + } + } + + /** + * @param bool $isHaltOnError + * + * @return Traversable + * @throws BaseException + * @throws Exceptions\InvalidArgumentException + * @throws \JsonException + * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + */ + private function getTraversableBatchResults(bool $isHaltOnError): Traversable + { + $this->log->debug( + 'getTraversableBatchResults.start', + [ + 'commandsCount' => $this->commands->count(), + 'isHaltOnError' => $isHaltOnError, + ] + ); + + // todo check unique names if exists + // конвертируем во внутренние представление батч-команд + $apiCommands = $this->convertToApiCommands(); + $batchQueryCounter = 0; + while (count($apiCommands)) { + $batchQuery = array_splice($apiCommands, 0, self::MAX_BATCH_PACKET_SIZE); + $this->log->debug( + 'getTraversableBatchResults.batchQuery', + [ + 'batchQueryNumber' => $batchQueryCounter, + 'queriesCount' => count($batchQuery), + ] + ); + // batch call + $batchResult = $this->coreService->call('batch', ['halt' => $isHaltOnError, 'cmd' => $batchQuery]); + // todo analyze batch result and halt on error + + $batchQueryCounter++; + yield $batchResult; + } + $this->log->debug('getTraversableBatchResults.finish'); + } + + /** + * @return array + */ + private function convertToApiCommands(): array + { + $apiCommands = []; + foreach ($this->commands as $itemCommand) { + /** + * @var $itemCommand Command + */ + $apiCommands[$itemCommand->getName() ?? $itemCommand->getUuid()->toString()] = sprintf( + '%s?%s', + $itemCommand->getApiMethod(), + http_build_query($itemCommand->getParameters()) + ); + } + + return $apiCommands; + } +} \ No newline at end of file diff --git a/src/Core/Commands/Command.php b/src/Core/Commands/Command.php new file mode 100644 index 00000000..e542b4dd --- /dev/null +++ b/src/Core/Commands/Command.php @@ -0,0 +1,82 @@ +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/Commands/CommandCollection.php b/src/Core/Commands/CommandCollection.php new file mode 100644 index 00000000..01930847 --- /dev/null +++ b/src/Core/Commands/CommandCollection.php @@ -0,0 +1,19 @@ +apiClient = $apiClient; + $this->eventDispatcher = $eventDispatcher; + $this->log = $log; + } + + /** + * @param string $apiMethod + * @param array $parameters + * + * @return Response + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + * @throws \JsonException + * @throws BaseException + */ + public function call(string $apiMethod, array $parameters = []): Response + { + $this->log->debug( + 'call.start', + [ + 'method' => $apiMethod, + 'parameters' => $parameters, + ] + ); + + // make async request + $apiCallResult = $this->apiClient->getResponse($apiMethod, $parameters); + + $response = null; + switch ($apiCallResult->getStatusCode()) { + case StatusCodeInterface::STATUS_OK: + //todo check with empty response size from server + $response = new Response($apiCallResult, $this->log); + break; + case StatusCodeInterface::STATUS_UNAUTHORIZED: + $body = $apiCallResult->toArray(false); + $this->log->notice( + 'UNAUTHORIZED request', + [ + 'body' => $body, + ] + ); + + if ($body['error'] === 'expired_token') { + // renew access token + $renewedToken = $this->apiClient->getNewAccessToken(); + $this->log->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->log->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'); + } + } + $this->log->debug('call.finish'); + + return $response; + } +} \ No newline at end of file diff --git a/src/Core/Response/DTO/ResponseDataCollection.php b/src/Core/Response/DTO/ResponseDataCollection.php new file mode 100644 index 00000000..da7d35f3 --- /dev/null +++ b/src/Core/Response/DTO/ResponseDataCollection.php @@ -0,0 +1,18 @@ +handleApiLevelErrors($responseResult); + if (!is_array($responseResult['result'])) { + $responseResult['result'] = [$responseResult['result']]; + } $resultDto = new DTO\Result($responseResult['result']); $time = DTO\Time::initFromResponse($responseResult['time']); $this->responseData = new DTO\ResponseData( $resultDto, $time ); - } catch (\Throwable $e) { + } catch (Throwable $e) { $this->logger->error( $e->getMessage(), [ diff --git a/src/Services/AbstractService.php b/src/Services/AbstractService.php new file mode 100644 index 00000000..123ff4ad --- /dev/null +++ b/src/Services/AbstractService.php @@ -0,0 +1,37 @@ +core = $core; + $this->log = $log; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deals/Service/Deals.php b/src/Services/CRM/Deals/Service/Deals.php new file mode 100644 index 00000000..8af9a102 --- /dev/null +++ b/src/Services/CRM/Deals/Service/Deals.php @@ -0,0 +1,55 @@ +log->debug( + 'deals.add.start', + [ + 'fields' => $fields, + 'params' => $params, + ] + ); + + $result = $this->core->call( + 'crm.deal.add', + [ + 'fields' => $fields, + 'params' => $params, + ] + ); + + $this->log->debug('deals.add.finish'); + + return $result->getResponseData()->getResult()->getResultData()[0]; + } + + public function get(int $id): array + { + $this->log->debug( + 'deals.get.start', + [ + 'id' => $id, + ] + ); + + $response = $this->core->call('crm.deal.get', ['id' => $id]); + + + $this->log->debug('deals.get.finish'); + + return $response->getResponseData()->getResult()->getResultData(); + } +} \ No newline at end of file diff --git a/src/Services/Main.php b/src/Services/Main.php index 30f001d3..6c3edac9 100644 --- a/src/Services/Main.php +++ b/src/Services/Main.php @@ -4,118 +4,40 @@ namespace Bitrix24\SDK\Services; -use Bitrix24\SDK\Core\ApiClient; -use Bitrix24\SDK\Core\Exceptions\BaseException; -use Bitrix24\SDK\Core\Response\Response; -use Bitrix24\SDK\Events\AuthTokenRenewedEvent; -use Fig\Http\Message\StatusCodeInterface; -use Psr\Log\LoggerInterface; -use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; - /** * Class Main * * @package Bitrix24\SDK\Services */ -class Main +class Main extends AbstractService { - /** - * @var ApiClient - */ - protected $apiClient; - /** - * @var LoggerInterface - */ - protected $log; - /** - * @var EventDispatcherInterface - */ - protected $eventDispatcher; - - /** - * Main constructor. - * - * @param ApiClient $apiClient - * @param EventDispatcherInterface $eventDispatcher - * @param LoggerInterface $log - */ - public function __construct(ApiClient $apiClient, EventDispatcherInterface $eventDispatcher, LoggerInterface $log) + public function getAvailableMethods(): array { - $this->apiClient = $apiClient; - $this->eventDispatcher = $eventDispatcher; - $this->log = $log; + return $this->core->call('methods', [])->getResponseData()->getResult()->getResultData(); } - /** - * @param string $apiMethod - * @param array $parameters - * - * @return Response - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException - * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface - * @throws \JsonException - * @throws BaseException - */ - public function call(string $apiMethod, array $parameters = []): Response + public function getAllMethods(): array { - $this->log->debug( - 'call.start', - [ - 'method' => $apiMethod, - 'parameters' => $parameters, - ] - ); - - // make async request - $apiCallResult = $this->apiClient->getResponse($apiMethod, $parameters); - - $response = null; - switch ($apiCallResult->getStatusCode()) { - case StatusCodeInterface::STATUS_OK: - //todo check with empty response size from server - $response = new Response($apiCallResult, $this->log); - break; - case StatusCodeInterface::STATUS_UNAUTHORIZED: - $body = $apiCallResult->toArray(false); - $this->log->notice( - 'UNAUTHORIZED request', - [ - 'body' => $body, - ] - ); + return $this->core->call('methods', ['full' => true])->getResponseData()->getResult()->getResultData(); + } - if ($body['error'] === 'expired_token') { - // renew access token - $renewedToken = $this->apiClient->getNewAccessToken(); - $this->log->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()); + public function getMethodsByScope(string $scopeName): array + { + return $this->core->call('methods', ['scope' => $scopeName])->getResponseData()->getResult()->getResultData(); + } - // repeat api-call - $response = $this->call($apiMethod, $parameters); - $this->log->debug( - 'api call repeated', - [ - 'repeatedApiMethod' => $apiMethod, - 'httpStatusCode' => $response->getHttpResponse()->getStatusCode(), - ] - ); + public function getApplicationInfo(): array + { + return $this->core->call('app.info')->getResponseData()->getResult()->getResultData(); + } - // dispatch event - $this->eventDispatcher->dispatch(new AuthTokenRenewedEvent($renewedToken)); - } else { - throw new BaseException('UNAUTHORIZED request error'); - } - } - $this->log->debug('call.finish'); + public function isCurrentUserHasAdminRights(): bool + { + return $this->core->call('user.admin')->getResponseData()->getResult()->getResultData()[0]; + } - return $response; + public function getUserProfile(): array + { + return $this->core->call('profile')->getResponseData()->getResult()->getResultData(); } } \ No newline at end of file From 0a960971f14b3ea41471f865193932a5814c6ac2 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 29 Nov 2020 22:20:19 +0300 Subject: [PATCH 167/647] add pagination DTO and list examp --- README.md | 8 ++- docs/RU/documentation.md | 8 ++- .../core/batch-query-iterable-read-examp.php | 57 ++++++++++++++++ src/Core/Batch.php | 8 ++- src/Core/Commands/Command.php | 2 +- src/Core/Core.php | 9 +-- src/Core/Response/DTO/Pagination.php | 50 ++++++++++++++ src/Core/Response/DTO/ResponseData.php | 22 +++++-- src/Core/Response/Response.php | 37 +++++++++-- src/Services/CRM/Deals/Service/Deals.php | 65 ++++++++++++++++++- 10 files changed, 244 insertions(+), 22 deletions(-) create mode 100644 examples/core/batch-query-iterable-read-examp.php create mode 100644 src/Core/Response/DTO/Pagination.php diff --git a/README.md b/README.md index 42d2fd94..ecdbc237 100644 --- a/README.md +++ b/README.md @@ -22,9 +22,10 @@ add low-level tools to devs: API - level features - ~~3.1 auto renew access tokens~~ -- 3.2 batch queries -- 3.3 offline queues -- 3.4 add change domain URL support +- 3.2 batch queries (work in progress) +- 3.3 list queries with «start=-1» support +- 3.4 offline queues +- 3.5 add change domain URL support Core DTO - ~~Response~~ @@ -32,6 +33,7 @@ Core DTO - ~~Time~~ - ~~OAuthToken~~ - ~~ApplicationProfile~~ +- ~~Pagination~~ ## SDK Documentation - [Russian](/docs/RU/documentation.md) diff --git a/docs/RU/documentation.md b/docs/RU/documentation.md index fb7e8616..f9c8855a 100644 --- a/docs/RU/documentation.md +++ b/docs/RU/documentation.md @@ -11,4 +11,10 @@ ## Обработка событий При работе с SDK могут возникать события, которые требуется обработать в клиентском коде. Библиотека позволяет подписаться на эти события с помощью компонента `EventDispatcher` -Список [событий](Core/Events/events.md), на которые можно подписаться. \ No newline at end of file +Список [событий](Core/Events/events.md), на которые можно подписаться. + +## Отправка запросов в пакетном режиме — batch +- работа с батч-запросами (wip) +- получение данных по фильтру +- получение больших объёмов (start=-1) + \ No newline at end of file diff --git a/examples/core/batch-query-iterable-read-examp.php b/examples/core/batch-query-iterable-read-examp.php new file mode 100644 index 00000000..5247c305 --- /dev/null +++ b/examples/core/batch-query-iterable-read-examp.php @@ -0,0 +1,57 @@ +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); + +$credentials = Bitrix24\SDK\Core\Credentials\Credentials::createForWebHook( + new \Bitrix24\SDK\Core\Credentials\WebhookUrl('') +); + +try { + $apiClient = new \Bitrix24\SDK\Core\ApiClient($credentials, $traceableClient, $log); + $ed = new \Symfony\Component\EventDispatcher\EventDispatcher(); + $core = new \Bitrix24\SDK\Core\Core($apiClient, $ed, $log); + $dealsService = new \Bitrix24\SDK\Services\CRM\Deals\Service\Deals($core, $log); + + + // пример вызова списочного метода c получением 50 элементов за один раз + $result = $dealsService->list( + [], + ['>ID' => 556], + ['ID', 'TITLE'], + 50 + ); + + var_dump($result->getResponseData()->getResult()->getResultData()); + var_dump($result->getResponseData()->getPagination()->getTotal()); + var_dump($result->getResponseData()->getPagination()->getNextPage()); + + + +} catch (\Throwable $exception) { + print(sprintf('ошибка: %s', $exception->getMessage()) . PHP_EOL); + print(sprintf('тип: %s', get_class($exception)) . PHP_EOL); + print(sprintf('trace: %s', $exception->getTraceAsString()) . PHP_EOL); +} + + + + + + + + + + diff --git a/src/Core/Batch.php b/src/Core/Batch.php index 013e11d2..95fd47b9 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -7,6 +7,7 @@ use Bitrix24\SDK\Core\Commands\Command; use Bitrix24\SDK\Core\Commands\CommandCollection; 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\Result; use Bitrix24\SDK\Core\Response\DTO\Time; @@ -105,7 +106,12 @@ public function getTraversable(bool $isHaltOnError): Traversable throw new BaseException(sprintf('query time with key %s not found', $singleQueryKey)); } - yield new ResponseData(new Result($singleQueryResult), Time::initFromResponse($resultQueryTimeItems[$singleQueryKey])); + // todo, посмотреть, что будет постраничке для батч-запросов на чтение + yield new ResponseData( + new Result($singleQueryResult), + Time::initFromResponse($resultQueryTimeItems[$singleQueryKey]), + new Pagination(null, null) + ); } } } diff --git a/src/Core/Commands/Command.php b/src/Core/Commands/Command.php index e542b4dd..471bb9dd 100644 --- a/src/Core/Commands/Command.php +++ b/src/Core/Commands/Command.php @@ -40,7 +40,7 @@ class Command * * @throws \Exception */ - public function __construct(string $apiMethod, array $parameters, ?string $name=null) + public function __construct(string $apiMethod, array $parameters, ?string $name = null) { $this->uuid = Uuid::uuid4(); $this->apiMethod = $apiMethod; diff --git a/src/Core/Core.php b/src/Core/Core.php index ad00b37c..df0c9c57 100644 --- a/src/Core/Core.php +++ b/src/Core/Core.php @@ -4,6 +4,7 @@ namespace Bitrix24\SDK\Core; +use Bitrix24\SDK\Core\Commands\Command; use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Response\Response; use Bitrix24\SDK\Events\AuthTokenRenewedEvent; @@ -66,16 +67,16 @@ public function call(string $apiMethod, array $parameters = []): Response ); // make async request - $apiCallResult = $this->apiClient->getResponse($apiMethod, $parameters); + $apiCallResponse = $this->apiClient->getResponse($apiMethod, $parameters); $response = null; - switch ($apiCallResult->getStatusCode()) { + switch ($apiCallResponse->getStatusCode()) { case StatusCodeInterface::STATUS_OK: //todo check with empty response size from server - $response = new Response($apiCallResult, $this->log); + $response = new Response($apiCallResponse, new Command($apiMethod, $parameters), $this->log); break; case StatusCodeInterface::STATUS_UNAUTHORIZED: - $body = $apiCallResult->toArray(false); + $body = $apiCallResponse->toArray(false); $this->log->notice( 'UNAUTHORIZED request', [ diff --git a/src/Core/Response/DTO/Pagination.php b/src/Core/Response/DTO/Pagination.php new file mode 100644 index 00000000..e18be270 --- /dev/null +++ b/src/Core/Response/DTO/Pagination.php @@ -0,0 +1,50 @@ +nextPage = $nextPage; + $this->total = $total; + } + + /** + * @return int|null + */ + public function getNextPage(): ?int + { + return $this->nextPage; + } + + /** + * @return int|null + */ + public function getTotal(): ?int + { + return $this->total; + } +} \ No newline at end of file diff --git a/src/Core/Response/DTO/ResponseData.php b/src/Core/Response/DTO/ResponseData.php index 1931f190..2605748a 100644 --- a/src/Core/Response/DTO/ResponseData.php +++ b/src/Core/Response/DTO/ResponseData.php @@ -19,17 +19,31 @@ class ResponseData * @var Time */ protected $time; + /** + * @var Pagination + */ + protected $pagination; /** - * Response constructor. + * ResponseData constructor. * - * @param Result $result - * @param Time $time + * @param Result $result + * @param Time $time + * @param Pagination $pagination */ - public function __construct(Result $result, Time $time) + public function __construct(Result $result, Time $time, Pagination $pagination) { $this->result = $result; $this->time = $time; + $this->pagination = $pagination; + } + + /** + * @return Pagination + */ + public function getPagination(): Pagination + { + return $this->pagination; } /** diff --git a/src/Core/Response/Response.php b/src/Core/Response/Response.php index 64e40e81..2cbfa4ec 100644 --- a/src/Core/Response/Response.php +++ b/src/Core/Response/Response.php @@ -4,6 +4,7 @@ namespace Bitrix24\SDK\Core\Response; +use Bitrix24\SDK\Core\Commands\Command; use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Response\DTO; use Psr\Log\LoggerInterface; @@ -26,19 +27,25 @@ class Response */ protected $logger; /** - * @var DTO\ResponseData|null + * @var DTO\ResponseData */ protected $responseData; + /** + * @var Command + */ + protected $apiCommand; /** * Response constructor. * * @param ResponseInterface $httpResponse + * @param Command $apiCommand * @param LoggerInterface $logger */ - public function __construct(ResponseInterface $httpResponse, LoggerInterface $logger) + public function __construct(ResponseInterface $httpResponse, Command $apiCommand, LoggerInterface $logger) { $this->httpResponse = $httpResponse; + $this->apiCommand = $apiCommand; $this->logger = $logger; } @@ -50,6 +57,14 @@ public function getHttpResponse(): ResponseInterface return $this->httpResponse; } + /** + * @return Command + */ + public function getApiCommand(): Command + { + return $this->apiCommand; + } + /** * @return DTO\ResponseData * @throws BaseException @@ -65,17 +80,25 @@ public function getResponseData(): DTO\ResponseData if ($this->responseData === null) { try { $responseResult = $this->httpResponse->toArray(true); - $this->handleApiLevelErrors($responseResult); if (!is_array($responseResult['result'])) { $responseResult['result'] = [$responseResult['result']]; } - $resultDto = new DTO\Result($responseResult['result']); - $time = DTO\Time::initFromResponse($responseResult['time']); + + $nextPage = null; + $total = null; + if (array_key_exists('next', $responseResult)) { + $nextPage = (int)$responseResult['next']; + } + if (array_key_exists('total', $responseResult)) { + $total = (int)$responseResult['total']; + } + $this->responseData = new DTO\ResponseData( - $resultDto, - $time + new DTO\Result($responseResult['result']), + DTO\Time::initFromResponse($responseResult['time']), + new DTO\Pagination($nextPage, $total) ); } catch (Throwable $e) { $this->logger->error( diff --git a/src/Services/CRM/Deals/Service/Deals.php b/src/Services/CRM/Deals/Service/Deals.php index 8af9a102..6515af1e 100644 --- a/src/Services/CRM/Deals/Service/Deals.php +++ b/src/Services/CRM/Deals/Service/Deals.php @@ -4,6 +4,7 @@ namespace Bitrix24\SDK\Services\CRM\Deals\Service; +use Bitrix24\SDK\Core\Response\Response; use Bitrix24\SDK\Services\AbstractService; /** @@ -13,6 +14,57 @@ */ class Deals extends AbstractService { + /** + * Get list of deal items. + * + * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_list.php + * + * @param array $order - order of deal items + * @param array $filter - filter array + * @param array $select - array of collumns to select + * @param integer $startItem - entity number to start from (usually returned in 'next' field of previous 'crm.deal.list' API call) + * + * @return Response + */ + public function list(array $order, array $filter, array $select, int $startItem = 0): Response + { + $this->log->debug( + 'deals.list.start', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $startItem, + ] + ); + + $result = $this->core->call( + 'crm.deal.list', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $startItem, + ] + ); + $this->log->debug('deals.list.finish'); + + return $result; + } + + /** + * @param array $fields + * @param array $params + * + * @return int + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @throws \JsonException + * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + */ public function add(array $fields, array $params = []): int { $this->log->debug( @@ -36,6 +88,18 @@ public function add(array $fields, array $params = []): int return $result->getResponseData()->getResult()->getResultData()[0]; } + /** + * @param int $id + * + * @return array + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @throws \JsonException + * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + */ public function get(int $id): array { $this->log->debug( @@ -47,7 +111,6 @@ public function get(int $id): array $response = $this->core->call('crm.deal.get', ['id' => $id]); - $this->log->debug('deals.get.finish'); return $response->getResponseData()->getResult()->getResultData(); From 19546bb5c6e2edf2655a3dc42f08206d730b2afd Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 30 Nov 2020 01:57:44 +0300 Subject: [PATCH 168/647] add getTraversableList for batch calls --- .../core/batch-query-iterable-read-examp.php | 113 ++++++++++++--- .../core/batch-query-iterable-write-examp.php | 12 +- src/Core/Batch.php | 133 +++++++++++++++++- src/Core/Response/DTO/Pagination.php | 12 +- src/Core/Response/Response.php | 6 +- 5 files changed, 244 insertions(+), 32 deletions(-) diff --git a/examples/core/batch-query-iterable-read-examp.php b/examples/core/batch-query-iterable-read-examp.php index 5247c305..53287590 100644 --- a/examples/core/batch-query-iterable-read-examp.php +++ b/examples/core/batch-query-iterable-read-examp.php @@ -10,34 +10,115 @@ $log = new Logger('name'); $log->pushHandler(new StreamHandler('b24-api-client-debug.log', Logger::DEBUG)); +$log->pushProcessor(new \Monolog\Processor\MemoryUsageProcessor(true, true)); $client = HttpClient::create(['http_version' => '2.0']); -$traceableClient = new \Symfony\Component\HttpClient\TraceableHttpClient($client); -$traceableClient->setLogger($log); + +//$client = new \Symfony\Component\HttpClient\TraceableHttpClient($client); +//$client->setLogger($log); $credentials = Bitrix24\SDK\Core\Credentials\Credentials::createForWebHook( new \Bitrix24\SDK\Core\Credentials\WebhookUrl('') ); try { - $apiClient = new \Bitrix24\SDK\Core\ApiClient($credentials, $traceableClient, $log); + $apiClient = new \Bitrix24\SDK\Core\ApiClient($credentials, $client, $log); $ed = new \Symfony\Component\EventDispatcher\EventDispatcher(); $core = new \Bitrix24\SDK\Core\Core($apiClient, $ed, $log); $dealsService = new \Bitrix24\SDK\Services\CRM\Deals\Service\Deals($core, $log); - - // пример вызова списочного метода c получением 50 элементов за один раз - $result = $dealsService->list( - [], - ['>ID' => 556], - ['ID', 'TITLE'], - 50 - ); - - var_dump($result->getResponseData()->getResult()->getResultData()); - var_dump($result->getResponseData()->getPagination()->getTotal()); - var_dump($result->getResponseData()->getPagination()->getNextPage()); - + // примеры формирования батч-запросов на чтение + // задача: прочитать все сделки из Б24 + + // простая стратегия (с подсчётом количества элементов на стороне Б24 на каждом шаге): + $timeStart = microtime(true); + $batch = new \Bitrix24\SDK\Core\Batch($core, $log); + foreach ($batch->getTraversableList('crm.deal.list', [], ['>ID' => 50], ['ID', 'TITLE']) as $cnt => $queryItem) { + print(sprintf(' %s | %s - %s', $cnt, $queryItem['ID'], $queryItem['TITLE']) . PHP_EOL); + } + $timeEnd = microtime(true); + print(sprintf('batch query duration: %s seconds', round($timeEnd - $timeStart, 2)) . PHP_EOL . PHP_EOL); + + $firstResult = $dealsService->list([], ['>ID' => 2], ['ID', 'TITLE']); + print (sprintf('elements total count: %s', $firstResult->getResponseData()->getPagination()->getTotal()) . PHP_EOL); + + +// // пример вызова списочного метода c получением 50 элементов за один раз +// print('list method example: ' . PHP_EOL); +// $result = $dealsService->list( +// [], +// ['>ID' => 2], +// ['ID', 'TITLE'], +// 50 +// ); +// var_dump($result->getResponseData()->getResult()->getResultData()); +// print(sprintf('duration: %s', $result->getResponseData()->getTime()->getDuration()) . PHP_EOL); +// print(sprintf('total elements: %s', $result->getResponseData()->getPagination()->getTotal()) . PHP_EOL); +// print(sprintf('next item: %s', $result->getResponseData()->getPagination()->getNextItem()) . PHP_EOL); +// print('=====' . PHP_EOL); +// +// +// // https://dev.1c-bitrix.ru/rest_help/rest_sum/start.php +// print('list method example without elements countable: ' . PHP_EOL); +// $result = $dealsService->list( +// [], +// ['>ID' => 2], +// ['ID', 'TITLE'], +// -1 +// ); +// var_dump($result->getResponseData()->getResult()->getResultData()); +// print(sprintf('duration: %s', $result->getResponseData()->getTime()->getDuration()) . PHP_EOL); +// print(sprintf('total elements: %s', $result->getResponseData()->getPagination()->getTotal()) . PHP_EOL); +// print(sprintf('next item: %s', $result->getResponseData()->getPagination()->getNextItem()) . PHP_EOL); +// +// $apiMethod = 'crm.deal.list'; +// +// $nextItem = $firstResult->getResponseData()->getPagination()->getNextItem(); +// $total = $firstResult->getResponseData()->getPagination()->getTotal(); +// +// +// for ($startItem = $nextItem; $startItem < $total; $startItem += $nextItem) { +// $batch->addCommand( +// $apiMethod, +// [ +// 'order' => [], +// 'filter' => ['>ID' => 2], +// 'select' => ['ID', 'TITLE'], +// 'start' => $startItem, +// ] +// ); +// } +// +// +// foreach ($batch->getTraversable(true) as $queryCnt => $queryResultData) { +// /** +// * @var $queryResultData \Bitrix24\SDK\Core\Response\DTO\ResponseData +// */ +// +// print(sprintf(' batch query number %s: ', $queryCnt) . PHP_EOL); +// print(sprintf( +// ' time |start: %s |duration %s |', +// $queryResultData->getTime()->getDateStart()->format('H:i:s'), +// $queryResultData->getTime()->getDuration(), +// ) . PHP_EOL); +// +// +// var_dump($queryResultData->getResult()->getResultData()); +// var_dump($queryResultData->getPagination()->getNextItem()); +// var_dump($queryResultData->getPagination()->getTotal()); +//// var_dump($queryResultData->getResult()->getResultData()); +// } + + // ------------------------------------------------------------------------------ + // пока не делаем, т.к. нет понимания как будет использоваться в клиентском коде + // стратегия (без подсчёта) (-1) + // 1. делаем первую выборку + // 2. проверяем условия достижения окончания ( + // !!!! при этом необходимо: + // - отсортировать записи по ID и добавить в фильтр условие ID > значения последнего элемента и с каждым шагом увеличивать его значение. + // - значение же последнего элемента брать из последнего значения полученного результата. + // - условием остановки импорта будет пустой ответ, или то, что в ответе элементов меньше 50. + // продумать кейсы: (выборки элементов), передача \ чтение результатов с автоподстановкой и т.д } catch (\Throwable $exception) { diff --git a/examples/core/batch-query-iterable-write-examp.php b/examples/core/batch-query-iterable-write-examp.php index 932a1a44..cf653f79 100644 --- a/examples/core/batch-query-iterable-write-examp.php +++ b/examples/core/batch-query-iterable-write-examp.php @@ -10,21 +10,25 @@ $log = new Logger('name'); $log->pushHandler(new StreamHandler('b24-api-client-debug.log', Logger::DEBUG)); +$log->pushProcessor(new \Monolog\Processor\MemoryUsageProcessor(true, true)); $client = HttpClient::create(['http_version' => '2.0']); -$traceableClient = new \Symfony\Component\HttpClient\TraceableHttpClient($client); -$traceableClient->setLogger($log); +//$httpClient = new \Symfony\Component\HttpClient\TraceableHttpClient($client); +//$httpClient->setLogger($log); + +// $httpClient = HttpClient::create(); + $credentials = Bitrix24\SDK\Core\Credentials\Credentials::createForWebHook( new \Bitrix24\SDK\Core\Credentials\WebhookUrl('https://') ); try { - $apiClient = new \Bitrix24\SDK\Core\ApiClient($credentials, $traceableClient, $log); + $apiClient = new \Bitrix24\SDK\Core\ApiClient($credentials, $httpClient, $log); $ed = new \Symfony\Component\EventDispatcher\EventDispatcher(); $core = new \Bitrix24\SDK\Core\Core($apiClient, $ed, $log); - $arraySize = 120; + $arraySize = 10000; print(sprintf('Prepare raw data example...') . PHP_EOL); $rawDeals = []; for ($i = 0; $i < $arraySize; $i++) { diff --git a/src/Core/Batch.php b/src/Core/Batch.php index 95fd47b9..e4b1f891 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -57,7 +57,14 @@ public function __construct(Core $core, LoggerInterface $log) */ public function clearCommands(): void { + $this->log->debug( + 'clearCommands.start', + [ + 'commandsCount' => $this->commands->count(), + ] + ); $this->commands = new CommandCollection(); + $this->log->debug('clearCommands.finish'); } /** @@ -76,28 +83,138 @@ public function addCommand( ?string $commandName = null, callable $callback = null ) { + $this->log->debug( + 'addCommand.start', + [ + 'apiMethod' => $apiMethod, + 'parameters' => $parameters, + 'commandName' => $commandName, + ] + ); + $this->commands->attach(new Command($apiMethod, $parameters, $commandName)); + + $this->log->debug( + 'addCommand.finish', + [ + 'commandsCount' => $this->commands->count(), + ] + ); + } + + /** + * @param string $apiMethod + * @param array $order + * @param array $filter + * @param array $select + * + * @return Traversable + * @throws BaseException + * @throws Exceptions\InvalidArgumentException + * @throws \JsonException + * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + */ + public function getTraversableList(string $apiMethod, array $order, array $filter, array $select): Traversable + { + $this->log->debug( + 'getTraversableList.start', + [ + 'apiMethod' => $apiMethod, + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + ] + ); + $this->clearCommands(); + + // get total elements count + $firstResult = $this->coreService->call( + $apiMethod, + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => 0, + ] + ); + $nextItem = $firstResult->getResponseData()->getPagination()->getNextItem(); + $total = $firstResult->getResponseData()->getPagination()->getTotal(); + + // register list commands + for ($startItem = 0; $startItem < $total; $startItem += $nextItem) { + $this->addCommand( + $apiMethod, + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $startItem, + ] + ); + } + + // iterate batch queries + foreach ($this->getTraversable(true) as $queryCnt => $queryResultData) { + /** + * @var $queryResultData \Bitrix24\SDK\Core\Response\DTO\ResponseData + */ + // iterate items in query result + foreach ($queryResultData->getResult()->getResultData() as $cnt => $listElement) { + yield $listElement; + } + } + + $this->log->debug('getTraversableList.finish'); } /** * @param bool $isHaltOnError * - * @return Response + * @return Traversable * @throws BaseException * @throws Exceptions\InvalidArgumentException * @throws \JsonException + * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface */ public function getTraversable(bool $isHaltOnError): Traversable { + $this->log->debug( + 'getTraversable.start', + [ + 'isHaltOnError' => $isHaltOnError, + ] + ); + foreach ($this->getTraversableBatchResults($isHaltOnError) as $batchItem => $batchResult) { /** * @var $batchResult Response */ + $this->log->debug( + 'getTraversable.batchResultItem.processStart', + [ + 'batchItemNumber' => $batchItem, + // 'batchApiCommand' => $batchResult->getApiCommand()->getApiMethod(), + // 'batchApiCommandParameters' => $batchResult->getApiCommand()->getParameters(), + ] + ); $response = $batchResult->getResponseData(); + // single queries + // todo handle error field $resultDataItems = $response->getResult()->getResultData()['result']; $resultQueryTimeItems = $response->getResult()->getResultData()['result_time']; + + // list queries + //todo handle result_error for list queries + $resultNextItems = $response->getResult()->getResultData()['result_next']; + $totalItems = $response->getResult()->getResultData()['result_total']; + foreach ($resultDataItems as $singleQueryKey => $singleQueryResult) { if (!is_array($singleQueryResult)) { $singleQueryResult = [$singleQueryResult]; @@ -106,14 +223,24 @@ public function getTraversable(bool $isHaltOnError): Traversable throw new BaseException(sprintf('query time with key %s not found', $singleQueryKey)); } - // todo, посмотреть, что будет постраничке для батч-запросов на чтение + $nextItem = null; + if ($resultNextItems !== null && count($resultNextItems) > 0) { + $nextItem = $resultNextItems[$singleQueryKey]; + } + $total = null; + if ($totalItems !== null && count($totalItems) > 0) { + $total = $totalItems[$singleQueryKey]; + } + yield new ResponseData( new Result($singleQueryResult), Time::initFromResponse($resultQueryTimeItems[$singleQueryKey]), - new Pagination(null, null) + new Pagination($nextItem, $total) ); } + $this->log->debug('getTraversable.batchResult.processFinish'); } + $this->log->debug('getTraversable.finish'); } /** diff --git a/src/Core/Response/DTO/Pagination.php b/src/Core/Response/DTO/Pagination.php index e18be270..eb0a5e4f 100644 --- a/src/Core/Response/DTO/Pagination.php +++ b/src/Core/Response/DTO/Pagination.php @@ -14,7 +14,7 @@ class Pagination /** * @var int|null */ - private $nextPage; + private $nextItem; /** * @var int|null */ @@ -23,21 +23,21 @@ class Pagination /** * Pagination constructor. * - * @param int|null $nextPage + * @param int|null $nextItem * @param int|null $total */ - public function __construct(int $nextPage = null, int $total = null) + public function __construct(int $nextItem = null, int $total = null) { - $this->nextPage = $nextPage; + $this->nextItem = $nextItem; $this->total = $total; } /** * @return int|null */ - public function getNextPage(): ?int + public function getNextItem(): ?int { - return $this->nextPage; + return $this->nextItem; } /** diff --git a/src/Core/Response/Response.php b/src/Core/Response/Response.php index 2cbfa4ec..8b98211f 100644 --- a/src/Core/Response/Response.php +++ b/src/Core/Response/Response.php @@ -86,10 +86,10 @@ public function getResponseData(): DTO\ResponseData $responseResult['result'] = [$responseResult['result']]; } - $nextPage = null; + $nextItem = null; $total = null; if (array_key_exists('next', $responseResult)) { - $nextPage = (int)$responseResult['next']; + $nextItem = (int)$responseResult['next']; } if (array_key_exists('total', $responseResult)) { $total = (int)$responseResult['total']; @@ -98,7 +98,7 @@ public function getResponseData(): DTO\ResponseData $this->responseData = new DTO\ResponseData( new DTO\Result($responseResult['result']), DTO\Time::initFromResponse($responseResult['time']), - new DTO\Pagination($nextPage, $total) + new DTO\Pagination($nextItem, $total) ); } catch (Throwable $e) { $this->logger->error( From 082a14bf0f2b94b44f815686d5475adca3ea545d Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 5 Dec 2020 13:33:20 +0300 Subject: [PATCH 169/647] fix errors --- .../core/batch-query-iterable-read-examp.php | 54 ++++--------------- src/Core/Batch.php | 44 ++++++++++----- 2 files changed, 42 insertions(+), 56 deletions(-) diff --git a/examples/core/batch-query-iterable-read-examp.php b/examples/core/batch-query-iterable-read-examp.php index 53287590..b6179812 100644 --- a/examples/core/batch-query-iterable-read-examp.php +++ b/examples/core/batch-query-iterable-read-examp.php @@ -27,20 +27,25 @@ $core = new \Bitrix24\SDK\Core\Core($apiClient, $ed, $log); $dealsService = new \Bitrix24\SDK\Services\CRM\Deals\Service\Deals($core, $log); + + $firstResult = $dealsService->list([], ['>ID' => 50], ['ID', 'TITLE']); + $totalCount = $firstResult->getResponseData()->getPagination()->getTotal(); + + // примеры формирования батч-запросов на чтение // задача: прочитать все сделки из Б24 - // простая стратегия (с подсчётом количества элементов на стороне Б24 на каждом шаге): $timeStart = microtime(true); $batch = new \Bitrix24\SDK\Core\Batch($core, $log); - foreach ($batch->getTraversableList('crm.deal.list', [], ['>ID' => 50], ['ID', 'TITLE']) as $cnt => $queryItem) { - print(sprintf(' %s | %s - %s', $cnt, $queryItem['ID'], $queryItem['TITLE']) . PHP_EOL); + $elementsFromBatchCount = 0; + foreach ($batch->getTraversableList('crm.deal.list', [], ['>ID' => 50], ['ID', 'TITLE']) as $queryItem) { + $elementsFromBatchCount++; + print(sprintf(' %s | %s - %s', $elementsFromBatchCount, $queryItem['ID'], $queryItem['TITLE']) . PHP_EOL); } $timeEnd = microtime(true); print(sprintf('batch query duration: %s seconds', round($timeEnd - $timeStart, 2)) . PHP_EOL . PHP_EOL); - - $firstResult = $dealsService->list([], ['>ID' => 2], ['ID', 'TITLE']); - print (sprintf('elements total count: %s', $firstResult->getResponseData()->getPagination()->getTotal()) . PHP_EOL); + print(sprintf('elements in bitrix24 count: %s', $totalCount) . PHP_EOL); + print(sprintf('elements from batch count: %s ', $elementsFromBatchCount) . PHP_EOL . PHP_EOL); // // пример вызова списочного метода c получением 50 элементов за один раз @@ -71,43 +76,6 @@ // print(sprintf('total elements: %s', $result->getResponseData()->getPagination()->getTotal()) . PHP_EOL); // print(sprintf('next item: %s', $result->getResponseData()->getPagination()->getNextItem()) . PHP_EOL); // -// $apiMethod = 'crm.deal.list'; -// -// $nextItem = $firstResult->getResponseData()->getPagination()->getNextItem(); -// $total = $firstResult->getResponseData()->getPagination()->getTotal(); -// -// -// for ($startItem = $nextItem; $startItem < $total; $startItem += $nextItem) { -// $batch->addCommand( -// $apiMethod, -// [ -// 'order' => [], -// 'filter' => ['>ID' => 2], -// 'select' => ['ID', 'TITLE'], -// 'start' => $startItem, -// ] -// ); -// } -// -// -// foreach ($batch->getTraversable(true) as $queryCnt => $queryResultData) { -// /** -// * @var $queryResultData \Bitrix24\SDK\Core\Response\DTO\ResponseData -// */ -// -// print(sprintf(' batch query number %s: ', $queryCnt) . PHP_EOL); -// print(sprintf( -// ' time |start: %s |duration %s |', -// $queryResultData->getTime()->getDateStart()->format('H:i:s'), -// $queryResultData->getTime()->getDuration(), -// ) . PHP_EOL); -// -// -// var_dump($queryResultData->getResult()->getResultData()); -// var_dump($queryResultData->getPagination()->getNextItem()); -// var_dump($queryResultData->getPagination()->getTotal()); -//// var_dump($queryResultData->getResult()->getResultData()); -// } // ------------------------------------------------------------------------------ // пока не делаем, т.к. нет понимания как будет использоваться в клиентском коде diff --git a/src/Core/Batch.php b/src/Core/Batch.php index e4b1f891..86e3030c 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -103,10 +103,12 @@ public function addCommand( } /** - * @param string $apiMethod - * @param array $order - * @param array $filter - * @param array $select + * batch wrapper for *.list methods + * + * @param string $apiMethod api command + * @param array $order [] field to order and order direction + * @param array $filter [] filter + * @param array $select [] fields to select * * @return Traversable * @throws BaseException @@ -116,6 +118,7 @@ public function addCommand( * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + * @throws \Exception */ public function getTraversableList(string $apiMethod, array $order, array $filter, array $select): Traversable { @@ -144,7 +147,7 @@ public function getTraversableList(string $apiMethod, array $order, array $filte $total = $firstResult->getResponseData()->getPagination()->getTotal(); // register list commands - for ($startItem = 0; $startItem < $total; $startItem += $nextItem) { + for ($startItem = 0; $startItem <= $total; $startItem += $nextItem) { $this->addCommand( $apiMethod, [ @@ -155,13 +158,27 @@ public function getTraversableList(string $apiMethod, array $order, array $filte ] ); } + $this->log->debug( + 'getTraversableList.commandsRegistered', + [ + 'commandsCount' => $this->commands->count(), + 'totalItemsToSelect' => $total, + ] + ); - // iterate batch queries + // iterate batch queries, max: 50 results per 50 elements in each result foreach ($this->getTraversable(true) as $queryCnt => $queryResultData) { /** - * @var $queryResultData \Bitrix24\SDK\Core\Response\DTO\ResponseData + * @var $queryResultData ResponseData */ - // iterate items in query result + $this->log->debug( + 'getTraversableList.batchResultItem', + [ + 'batchCommandItemNumber' => $queryCnt, + 'nextItem' => $queryResultData->getPagination()->getNextItem(), + ] + ); + // iterate items in batch query result foreach ($queryResultData->getResult()->getResultData() as $cnt => $listElement) { yield $listElement; } @@ -181,6 +198,7 @@ public function getTraversableList(string $apiMethod, array $order, array $filte * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + * @throws \Exception */ public function getTraversable(bool $isHaltOnError): Traversable { @@ -198,9 +216,9 @@ public function getTraversable(bool $isHaltOnError): Traversable $this->log->debug( 'getTraversable.batchResultItem.processStart', [ - 'batchItemNumber' => $batchItem, - // 'batchApiCommand' => $batchResult->getApiCommand()->getApiMethod(), - // 'batchApiCommandParameters' => $batchResult->getApiCommand()->getParameters(), + 'batchItemNumber' => $batchItem, + 'batchApiCommand' => $batchResult->getApiCommand()->getApiMethod(), + 'batchApiCommandUuid' => $batchResult->getApiCommand()->getUuid()->toString(), ] ); $response = $batchResult->getResponseData(); @@ -214,7 +232,6 @@ public function getTraversable(bool $isHaltOnError): Traversable //todo handle result_error for list queries $resultNextItems = $response->getResult()->getResultData()['result_next']; $totalItems = $response->getResult()->getResultData()['result_total']; - foreach ($resultDataItems as $singleQueryKey => $singleQueryResult) { if (!is_array($singleQueryResult)) { $singleQueryResult = [$singleQueryResult]; @@ -224,9 +241,10 @@ public function getTraversable(bool $isHaltOnError): Traversable } $nextItem = null; - if ($resultNextItems !== null && count($resultNextItems) > 0) { + if ($resultNextItems !== null && array_key_exists($singleQueryKey, $resultNextItems) && count($resultNextItems) > 0) { $nextItem = $resultNextItems[$singleQueryKey]; } + $total = null; if ($totalItems !== null && count($totalItems) > 0) { $total = $totalItems[$singleQueryKey]; From 5c1395e6ccbe4f80844c1502b2b30b95cf614c99 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Dec 2020 00:22:21 +0300 Subject: [PATCH 170/647] add TransportException --- src/Core/Exceptions/TransportException.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/Core/Exceptions/TransportException.php diff --git a/src/Core/Exceptions/TransportException.php b/src/Core/Exceptions/TransportException.php new file mode 100644 index 00000000..d5c02064 --- /dev/null +++ b/src/Core/Exceptions/TransportException.php @@ -0,0 +1,16 @@ + Date: Sun, 6 Dec 2020 00:24:03 +0300 Subject: [PATCH 171/647] fix errors --- src/Core/ApiClient.php | 31 +++++++++-- src/Core/Batch.php | 44 ++++++++------- src/Core/Core.php | 118 ++++++++++++++++++++++++----------------- 3 files changed, 120 insertions(+), 73 deletions(-) diff --git a/src/Core/ApiClient.php b/src/Core/ApiClient.php index f0a09ab5..b95eb9f3 100644 --- a/src/Core/ApiClient.php +++ b/src/Core/ApiClient.php @@ -37,7 +37,8 @@ class ApiClient /** * @const string */ - protected const SDK_VERSION = '2.0'; + protected const SDK_VERSION = '2.0.0'; + protected const SDK_USER_AGENT = 'bitrix24-php-sdk'; /** * ApiClient constructor. @@ -51,6 +52,26 @@ public function __construct(Credentials\Credentials $credentials, HttpClientInte $this->credentials = $credentials; $this->client = $client; $this->logger = $logger; + $this->logger->debug( + 'ApiClient.init', + [ + 'httpClientType' => get_class($client), + ] + ); + } + + /** + * @return array + */ + protected function getDefaultHeaders(): array + { + return [ + 'Accept' => 'application/json', + 'Accept-Charset' => 'utf-8', + 'User-Agent' => sprintf('%s-v-%s-php-%s', self::SDK_USER_AGENT, self::SDK_VERSION, PHP_VERSION), + 'X-BITRIX24-PHP-SDK-PHP-VERSION' => PHP_VERSION, + 'X-BITRIX24-PHP-SDK-VERSION' => self::SDK_VERSION, + ]; } /** @@ -91,7 +112,10 @@ public function getNewAccessToken(): RenewedAccessToken ) ); - $response = $this->client->request($method, $url, []); + $requestOptions = [ + 'headers' => $this->getDefaultHeaders(), + ]; + $response = $this->client->request($method, $url, $requestOptions); $result = $response->toArray(false); $newAccessToken = RenewedAccessToken::initFromArray($result); @@ -131,7 +155,8 @@ public function getResponse(string $apiMethod, array $parameters = []): Response } $requestOptions = [ - 'json' => $parameters, + 'json' => $parameters, + 'headers' => $this->getDefaultHeaders(), ]; $response = $this->client->request($method, $url, $requestOptions); diff --git a/src/Core/Batch.php b/src/Core/Batch.php index 86e3030c..090eac08 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -12,8 +12,8 @@ use Bitrix24\SDK\Core\Response\DTO\Result; use Bitrix24\SDK\Core\Response\DTO\Time; use Bitrix24\SDK\Core\Response\Response; +use Generator; use Psr\Log\LoggerInterface; -use Traversable; /** * Class Batch @@ -105,22 +105,21 @@ public function addCommand( /** * batch wrapper for *.list methods * - * @param string $apiMethod api command - * @param array $order [] field to order and order direction - * @param array $filter [] filter - * @param array $select [] fields to select + * @param string $apiMethod + * @param array $order + * @param array $filter + * @param array $select + * @param int|null $limit * - * @return Traversable + * @return Generator * @throws BaseException - * @throws Exceptions\InvalidArgumentException - * @throws \JsonException + * @throws Exceptions\TransportException * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface - * @throws \Exception */ - public function getTraversableList(string $apiMethod, array $order, array $filter, array $select): Traversable + public function getTraversableList(string $apiMethod, array $order, array $filter, array $select, ?int $limit = null): Generator { $this->log->debug( 'getTraversableList.start', @@ -129,6 +128,7 @@ public function getTraversableList(string $apiMethod, array $order, array $filte 'order' => $order, 'filter' => $filter, 'select' => $select, + 'limit' => $limit, ] ); $this->clearCommands(); @@ -157,6 +157,9 @@ public function getTraversableList(string $apiMethod, array $order, array $filte 'start' => $startItem, ] ); + if ($limit !== null && $limit < $startItem) { + break; + } } $this->log->debug( 'getTraversableList.commandsRegistered', @@ -167,6 +170,7 @@ public function getTraversableList(string $apiMethod, array $order, array $filte ); // iterate batch queries, max: 50 results per 50 elements in each result + $elementsCounter = 0; foreach ($this->getTraversable(true) as $queryCnt => $queryResultData) { /** * @var $queryResultData ResponseData @@ -180,6 +184,10 @@ public function getTraversableList(string $apiMethod, array $order, array $filte ); // iterate items in batch query result foreach ($queryResultData->getResult()->getResultData() as $cnt => $listElement) { + $elementsCounter++; + if ($limit !== null && $elementsCounter > $limit) { + return; + } yield $listElement; } } @@ -190,17 +198,15 @@ public function getTraversableList(string $apiMethod, array $order, array $filte /** * @param bool $isHaltOnError * - * @return Traversable + * @return Generator * @throws BaseException - * @throws Exceptions\InvalidArgumentException - * @throws \JsonException + * @throws Exceptions\TransportException * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface - * @throws \Exception */ - public function getTraversable(bool $isHaltOnError): Traversable + public function getTraversable(bool $isHaltOnError): Generator { $this->log->debug( 'getTraversable.start', @@ -264,13 +270,11 @@ public function getTraversable(bool $isHaltOnError): Traversable /** * @param bool $isHaltOnError * - * @return Traversable + * @return Generator * @throws BaseException - * @throws Exceptions\InvalidArgumentException - * @throws \JsonException - * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + * @throws Exceptions\TransportException */ - private function getTraversableBatchResults(bool $isHaltOnError): Traversable + private function getTraversableBatchResults(bool $isHaltOnError): Generator { $this->log->debug( 'getTraversableBatchResults.start', diff --git a/src/Core/Core.php b/src/Core/Core.php index df0c9c57..a6fb4c11 100644 --- a/src/Core/Core.php +++ b/src/Core/Core.php @@ -6,11 +6,13 @@ use Bitrix24\SDK\Core\Commands\Command; use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; use Bitrix24\SDK\Core\Response\Response; use Bitrix24\SDK\Events\AuthTokenRenewedEvent; use Fig\Http\Message\StatusCodeInterface; use Psr\Log\LoggerInterface; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; /** * Class Core @@ -26,7 +28,7 @@ class Core /** * @var LoggerInterface */ - protected $log; + protected $logger; /** * @var EventDispatcherInterface */ @@ -37,13 +39,13 @@ class Core * * @param ApiClient $apiClient * @param EventDispatcherInterface $eventDispatcher - * @param LoggerInterface $log + * @param LoggerInterface $logger */ - public function __construct(ApiClient $apiClient, EventDispatcherInterface $eventDispatcher, LoggerInterface $log) + public function __construct(ApiClient $apiClient, EventDispatcherInterface $eventDispatcher, LoggerInterface $logger) { $this->apiClient = $apiClient; $this->eventDispatcher = $eventDispatcher; - $this->log = $log; + $this->logger = $logger; } /** @@ -51,14 +53,12 @@ public function __construct(ApiClient $apiClient, EventDispatcherInterface $even * @param array $parameters * * @return Response - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException - * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface - * @throws \JsonException * @throws BaseException + * @throws TransportException */ public function call(string $apiMethod, array $parameters = []): Response { - $this->log->debug( + $this->logger->debug( 'call.start', [ 'method' => $apiMethod, @@ -66,55 +66,73 @@ public function call(string $apiMethod, array $parameters = []): Response ] ); - // make async request - $apiCallResponse = $this->apiClient->getResponse($apiMethod, $parameters); - $response = null; - switch ($apiCallResponse->getStatusCode()) { - case StatusCodeInterface::STATUS_OK: - //todo check with empty response size from server - $response = new Response($apiCallResponse, new Command($apiMethod, $parameters), $this->log); - break; - case StatusCodeInterface::STATUS_UNAUTHORIZED: - $body = $apiCallResponse->toArray(false); - $this->log->notice( - 'UNAUTHORIZED request', - [ - 'body' => $body, - ] - ); - - if ($body['error'] === 'expired_token') { - // renew access token - $renewedToken = $this->apiClient->getNewAccessToken(); - $this->log->debug( - 'access token renewed', + try { + // make async request + $apiCallResponse = $this->apiClient->getResponse($apiMethod, $parameters); + switch ($apiCallResponse->getStatusCode()) { + case StatusCodeInterface::STATUS_OK: + //todo check with empty response size from server + $response = new Response($apiCallResponse, new Command($apiMethod, $parameters), $this->logger); + break; + case StatusCodeInterface::STATUS_UNAUTHORIZED: + $body = $apiCallResponse->toArray(false); + $this->logger->notice( + 'UNAUTHORIZED request', [ - 'newAccessToken' => $renewedToken->getAccessToken()->getAccessToken(), - 'newRefreshToken' => $renewedToken->getAccessToken()->getRefreshToken(), - 'newExpires' => $renewedToken->getAccessToken()->getExpires(), - 'appStatus' => $renewedToken->getApplicationStatus(), + 'body' => $body, ] ); - $this->apiClient->getCredentials()->setAccessToken($renewedToken->getAccessToken()); - // repeat api-call - $response = $this->call($apiMethod, $parameters); - $this->log->debug( - 'api call repeated', - [ - 'repeatedApiMethod' => $apiMethod, - 'httpStatusCode' => $response->getHttpResponse()->getStatusCode(), - ] - ); + 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()); + + // 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)); + } else { + throw new BaseException('UNAUTHORIZED request error'); + } + } + } catch (TransportExceptionInterface $exception) { + $this->logger->error( + 'call.transportException', + [ + 'trace' => $exception->getTrace(), + 'message' => $exception->getMessage(), + ] + ); + throw new TransportException(sprintf('transport error - %s', $exception->getMessage()), $exception->getCode(), $exception); + } catch (\Throwable $exception) { + $this->logger->error( + 'call.unknownException', + [ + 'message' => $exception->getMessage(), + ] + ); + throw new BaseException(sprintf('unknown error - %s', $exception->getMessage()), $exception->getCode(), $exception); } - $this->log->debug('call.finish'); + $this->logger->debug('call.finish'); return $response; } From 2061b2afe0cc4639231508cdebfd880be55ec5fe Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 7 Dec 2020 01:52:33 +0300 Subject: [PATCH 172/647] update to 5.2 --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 24263d4d..f1877fa1 100644 --- a/composer.json +++ b/composer.json @@ -22,8 +22,8 @@ "ext-curl": "*", "psr/log": "1.1.3", "fig/http-message-util": "1.1.*", - "symfony/http-client": "5.1.*", - "symfony/event-dispatcher": "5.1.*", + "symfony/http-client": "5.2.*", + "symfony/event-dispatcher": "5.2.*", "ramsey/uuid": "^3.9.3" }, "require-dev": { From 5801a6784ccb5c9b07d3641f9d9000ce31b9de9b Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 7 Dec 2020 01:56:08 +0300 Subject: [PATCH 173/647] add new exceptions --- src/Core/Exceptions/MethodNotFoundException.php | 14 ++++++++++++++ .../Exceptions/QueryLimitExceededException.php | 14 ++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 src/Core/Exceptions/MethodNotFoundException.php create mode 100644 src/Core/Exceptions/QueryLimitExceededException.php diff --git a/src/Core/Exceptions/MethodNotFoundException.php b/src/Core/Exceptions/MethodNotFoundException.php new file mode 100644 index 00000000..892684b2 --- /dev/null +++ b/src/Core/Exceptions/MethodNotFoundException.php @@ -0,0 +1,14 @@ + Date: Mon, 7 Dec 2020 01:57:32 +0300 Subject: [PATCH 174/647] add ApiLevelErrorHandler --- src/Core/ApiClient.php | 2 +- src/Core/ApiLevelErrorHandler.php | 68 +++++++++++++++++++++++++++++++ src/Core/Core.php | 46 ++++++++++++++++++++- 3 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 src/Core/ApiLevelErrorHandler.php diff --git a/src/Core/ApiClient.php b/src/Core/ApiClient.php index b95eb9f3..72a5d626 100644 --- a/src/Core/ApiClient.php +++ b/src/Core/ApiClient.php @@ -161,7 +161,7 @@ public function getResponse(string $apiMethod, array $parameters = []): Response $response = $this->client->request($method, $url, $requestOptions); $this->logger->debug( - sprintf('getResponse.end %s', $apiMethod), + sprintf('getResponse.end [%s]', $apiMethod), [ 'responseInfo' => $response->getInfo(), ] diff --git a/src/Core/ApiLevelErrorHandler.php b/src/Core/ApiLevelErrorHandler.php new file mode 100644 index 00000000..0044cda0 --- /dev/null +++ b/src/Core/ApiLevelErrorHandler.php @@ -0,0 +1,68 @@ +logger = $logger; + } + + /** + * @param array $responseBody + * + * @throws QueryLimitExceededException + * @throws BaseException + */ + public function handle(array $responseBody): void + { + if (!array_key_exists(self::ERROR_KEY, $responseBody)) { + $this->logger->debug('handle.noError'); + + return; + } + $errorCode = strtolower(trim((string)$responseBody[self::ERROR_KEY])); + $errorDescription = strtolower(trim((string)$responseBody[self::ERROR_DESCRIPTION_KEY])); + $this->logger->debug( + 'handle.errorCode', + [ + 'errorCode' => $errorCode, + ] + ); + switch ($errorCode) { + case 'query_limit_exceeded': + throw new QueryLimitExceededException(sprintf('query limit exceeded - too many requests')); + case 'error_method_not_found': + throw new MethodNotFoundException(sprintf('api method not found')); + default: + throw new BaseException(sprintf('%s - %s', $errorCode, $errorDescription)); + } + } +} \ No newline at end of file diff --git a/src/Core/Core.php b/src/Core/Core.php index a6fb4c11..bdf16431 100644 --- a/src/Core/Core.php +++ b/src/Core/Core.php @@ -33,17 +33,27 @@ class Core * @var EventDispatcherInterface */ protected $eventDispatcher; + /** + * @var ApiLevelErrorHandler + */ + protected $apiLevelErrorHandler; /** * Main constructor. * * @param ApiClient $apiClient + * @param ApiLevelErrorHandler $apiLevelErrorHandler * @param EventDispatcherInterface $eventDispatcher * @param LoggerInterface $logger */ - public function __construct(ApiClient $apiClient, EventDispatcherInterface $eventDispatcher, LoggerInterface $logger) - { + public function __construct( + ApiClient $apiClient, + ApiLevelErrorHandler $apiLevelErrorHandler, + EventDispatcherInterface $eventDispatcher, + LoggerInterface $logger + ) { $this->apiClient = $apiClient; + $this->apiLevelErrorHandler = $apiLevelErrorHandler; $this->eventDispatcher = $eventDispatcher; $this->logger = $logger; } @@ -70,6 +80,12 @@ public function call(string $apiMethod, array $parameters = []): Response try { // make async request $apiCallResponse = $this->apiClient->getResponse($apiMethod, $parameters); + $this->logger->debug( + 'call.responseInfo', + [ + 'httpStatus' => $apiCallResponse->getStatusCode(), + ] + ); switch ($apiCallResponse->getStatusCode()) { case StatusCodeInterface::STATUS_OK: //todo check with empty response size from server @@ -113,8 +129,31 @@ public function call(string $apiMethod, array $parameters = []): Response } else { throw new BaseException('UNAUTHORIZED request error'); } + break; + case StatusCodeInterface::STATUS_SERVICE_UNAVAILABLE: + $body = $apiCallResponse->toArray(false); + $this->logger->notice( + 'bitrix24 portal unavailable', + [ + 'body' => $body, + ] + ); + $this->apiLevelErrorHandler->handle($body); + break; + default: + $body = $apiCallResponse->toArray(false); + $this->logger->notice( + 'unhandled server status', + [ + 'httpStatus' => $apiCallResponse->getStatusCode(), + 'body' => $body, + ] + ); + $this->apiLevelErrorHandler->handle($body); + break; } } catch (TransportExceptionInterface $exception) { + // catch symfony http client transport exception $this->logger->error( 'call.transportException', [ @@ -123,6 +162,9 @@ public function call(string $apiMethod, array $parameters = []): Response ] ); throw new TransportException(sprintf('transport error - %s', $exception->getMessage()), $exception->getCode(), $exception); + } catch (BaseException $exception) { + // rethrow known bitrix24 php sdk exception + throw $exception; } catch (\Throwable $exception) { $this->logger->error( 'call.unknownException', From 2401940aee37cec6924b2dbc0a9c8f5b1cfe2725 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 7 Dec 2020 01:57:44 +0300 Subject: [PATCH 175/647] add CoreBuilder --- src/Core/CoreBuilder.php | 147 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 src/Core/CoreBuilder.php diff --git a/src/Core/CoreBuilder.php b/src/Core/CoreBuilder.php new file mode 100644 index 00000000..495ea273 --- /dev/null +++ b/src/Core/CoreBuilder.php @@ -0,0 +1,147 @@ +logger = new NullLogger(); + $this->eventDispatcher = new EventDispatcher(); + $this->httpClient = HttpClient::create( + [ + 'http_version' => '2.0', + 'timeout' => 120, + ] + ); + $this->webhookUrl = null; + $this->credentials = null; + $this->apiClient = null; + $this->apiLevelErrorHandler = new ApiLevelErrorHandler($this->logger); + } + + /** + * @param string $webhookUrl + * + * @return $this + */ + public function withWebhookUrl(string $webhookUrl): self + { + $this->webhookUrl = new WebhookUrl($webhookUrl); + + return $this; + } + + /** + * @param ApiClient $apiClient + * + * @return $this + */ + public function withApiClient(ApiClient $apiClient): self + { + $this->apiClient = $apiClient; + + return $this; + } + + /** + * @param LoggerInterface $logger + * + * @return $this + */ + public function withLogger(LoggerInterface $logger): self + { + $this->logger = $logger; + + return $this; + } + + /** + * @param EventDispatcherInterface $eventDispatcher + * + * @return $this + */ + public function withEventDispatcher(EventDispatcherInterface $eventDispatcher): self + { + $this->eventDispatcher = $eventDispatcher; + + return $this; + } + + /** + * @return Core + * @throws InvalidArgumentException + */ + public function build(): Core + { + if ($this->webhookUrl !== null) { + $this->credentials = Credentials::createForWebHook($this->webhookUrl); + } elseif ($this->credentials === null) { + throw new InvalidArgumentException(sprintf('you must set webhook url or oauth credentials')); + } + + if ($this->apiClient === null) { + $this->apiClient = new ApiClient( + $this->credentials, + $this->httpClient, + $this->logger + ); + } + + return new Core( + $this->apiClient, + $this->apiLevelErrorHandler, + $this->eventDispatcher, + $this->logger + ); + } +} \ No newline at end of file From 1b7134f4d5f88c47489d738ee9f340095d41834a Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 14 Dec 2020 00:07:17 +0300 Subject: [PATCH 176/647] fix errors --- src/Core/Batch.php | 39 ++++++++++++++++++++---- src/Services/CRM/Deals/Service/Deals.php | 6 ++-- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/Core/Batch.php b/src/Core/Batch.php index 090eac08..19147fc6 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -34,6 +34,7 @@ class Batch * @var int */ protected const MAX_BATCH_PACKET_SIZE = 50; + protected const MAX_ELEMENTS_IN_PAGE = 50; /** * @var CommandCollection */ @@ -105,6 +106,8 @@ public function addCommand( /** * batch wrapper for *.list methods * + * work with start item position and elements count + * * @param string $apiMethod * @param array $order * @param array $filter @@ -143,24 +146,47 @@ public function getTraversableList(string $apiMethod, array $order, array $filte 'start' => 0, ] ); + $nextItem = $firstResult->getResponseData()->getPagination()->getNextItem(); $total = $firstResult->getResponseData()->getPagination()->getTotal(); - // register list commands - for ($startItem = 0; $startItem <= $total; $startItem += $nextItem) { + $this->log->debug( + 'getTraversableList.calculateCommandsRange', + [ + 'nextItem' => $nextItem, + 'totalItems' => $total, + ] + ); + + if ($total > self::MAX_ELEMENTS_IN_PAGE && $nextItem !== null) { + //more than one page in results - register list commands + for ($startItem = 0; $startItem <= $total; $startItem += $nextItem) { + $this->addCommand( + $apiMethod, + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $startItem, + ] + ); + if ($limit !== null && $limit < $startItem) { + break; + } + } + } else { + // one page in results $this->addCommand( $apiMethod, [ 'order' => $order, 'filter' => $filter, 'select' => $select, - 'start' => $startItem, + 'start' => 0, ] ); - if ($limit !== null && $limit < $startItem) { - break; - } } + $this->log->debug( 'getTraversableList.commandsRegistered', [ @@ -180,6 +206,7 @@ public function getTraversableList(string $apiMethod, array $order, array $filte [ 'batchCommandItemNumber' => $queryCnt, 'nextItem' => $queryResultData->getPagination()->getNextItem(), + 'durationTime' => $queryResultData->getTime()->getDuration(), ] ); // iterate items in batch query result diff --git a/src/Services/CRM/Deals/Service/Deals.php b/src/Services/CRM/Deals/Service/Deals.php index 6515af1e..7d8470fb 100644 --- a/src/Services/CRM/Deals/Service/Deals.php +++ b/src/Services/CRM/Deals/Service/Deals.php @@ -58,8 +58,7 @@ public function list(array $order, array $filter, array $select, int $startItem * * @return int * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException - * @throws \JsonException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface @@ -93,8 +92,7 @@ public function add(array $fields, array $params = []): int * * @return array * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException - * @throws \JsonException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface From db3115c1f76c559b753d2255a797431fb4041280 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 14 Dec 2020 00:09:04 +0300 Subject: [PATCH 177/647] add batch query read example --- .../core/batch-query-iterable-read-examp.php | 95 ++++++------------- 1 file changed, 30 insertions(+), 65 deletions(-) diff --git a/examples/core/batch-query-iterable-read-examp.php b/examples/core/batch-query-iterable-read-examp.php index b6179812..ca6eda18 100644 --- a/examples/core/batch-query-iterable-read-examp.php +++ b/examples/core/batch-query-iterable-read-examp.php @@ -2,93 +2,59 @@ declare(strict_types=1); require_once dirname(__DIR__, 2) . '/vendor/autoload.php'; -require_once 'vendor/autoload.php'; use Monolog\Handler\StreamHandler; use Monolog\Logger; -use Symfony\Component\HttpClient\HttpClient; -$log = new Logger('name'); -$log->pushHandler(new StreamHandler('b24-api-client-debug.log', Logger::DEBUG)); +$log = new Logger('examp'); +$log->pushHandler(new StreamHandler('examples/logs/b24-api-client.log', Logger::DEBUG)); $log->pushProcessor(new \Monolog\Processor\MemoryUsageProcessor(true, true)); - -$client = HttpClient::create(['http_version' => '2.0']); - -//$client = new \Symfony\Component\HttpClient\TraceableHttpClient($client); -//$client->setLogger($log); - -$credentials = Bitrix24\SDK\Core\Credentials\Credentials::createForWebHook( - new \Bitrix24\SDK\Core\Credentials\WebhookUrl('') -); +$log->pushProcessor(new \Monolog\Processor\IntrospectionProcessor()); +$log->debug('=============================================================='); try { - $apiClient = new \Bitrix24\SDK\Core\ApiClient($credentials, $client, $log); - $ed = new \Symfony\Component\EventDispatcher\EventDispatcher(); - $core = new \Bitrix24\SDK\Core\Core($apiClient, $ed, $log); - $dealsService = new \Bitrix24\SDK\Services\CRM\Deals\Service\Deals($core, $log); + print('получаем данные:' . PHP_EOL); + $core = (new \Bitrix24\SDK\Core\CoreBuilder()) + ->withLogger($log) + ->withWebhookUrl('') + ->build(); + $dealsService = new \Bitrix24\SDK\Services\CRM\Deals\Service\Deals($core, $log); - $firstResult = $dealsService->list([], ['>ID' => 50], ['ID', 'TITLE']); + $select = ['ID', 'TITLE']; + $firstResult = $dealsService->list([], ['>ID' => 50], $select); $totalCount = $firstResult->getResponseData()->getPagination()->getTotal(); // примеры формирования батч-запросов на чтение // задача: прочитать все сделки из Б24 // простая стратегия (с подсчётом количества элементов на стороне Б24 на каждом шаге): + + + $order = ['ID' => 'ASC']; + $filter = ['>ID' => 1]; + $select = ['ID', 'NAME', 'PHONE', 'EMAIL', 'IM']; + $timeStart = microtime(true); - $batch = new \Bitrix24\SDK\Core\Batch($core, $log); $elementsFromBatchCount = 0; - foreach ($batch->getTraversableList('crm.deal.list', [], ['>ID' => 50], ['ID', 'TITLE']) as $queryItem) { + $batch = new \Bitrix24\SDK\Core\Batch($core, $log); + foreach ($batch->getTraversableList('crm.contact.list', $order, $filter, $select, 6000) as $queryItem) { + $curTime = microtime(true); $elementsFromBatchCount++; - print(sprintf(' %s | %s - %s', $elementsFromBatchCount, $queryItem['ID'], $queryItem['TITLE']) . PHP_EOL); + print(sprintf( + '%s Mb| %s sec |item %s |%s - %s ', + round(memory_get_peak_usage(true) / 1024 / 1024, 2), + round($curTime - $timeStart, 2), + $elementsFromBatchCount, + $queryItem['ID'], + $queryItem['NAME'] + ) . PHP_EOL); } + $timeEnd = microtime(true); print(sprintf('batch query duration: %s seconds', round($timeEnd - $timeStart, 2)) . PHP_EOL . PHP_EOL); print(sprintf('elements in bitrix24 count: %s', $totalCount) . PHP_EOL); print(sprintf('elements from batch count: %s ', $elementsFromBatchCount) . PHP_EOL . PHP_EOL); - - -// // пример вызова списочного метода c получением 50 элементов за один раз -// print('list method example: ' . PHP_EOL); -// $result = $dealsService->list( -// [], -// ['>ID' => 2], -// ['ID', 'TITLE'], -// 50 -// ); -// var_dump($result->getResponseData()->getResult()->getResultData()); -// print(sprintf('duration: %s', $result->getResponseData()->getTime()->getDuration()) . PHP_EOL); -// print(sprintf('total elements: %s', $result->getResponseData()->getPagination()->getTotal()) . PHP_EOL); -// print(sprintf('next item: %s', $result->getResponseData()->getPagination()->getNextItem()) . PHP_EOL); -// print('=====' . PHP_EOL); -// -// -// // https://dev.1c-bitrix.ru/rest_help/rest_sum/start.php -// print('list method example without elements countable: ' . PHP_EOL); -// $result = $dealsService->list( -// [], -// ['>ID' => 2], -// ['ID', 'TITLE'], -// -1 -// ); -// var_dump($result->getResponseData()->getResult()->getResultData()); -// print(sprintf('duration: %s', $result->getResponseData()->getTime()->getDuration()) . PHP_EOL); -// print(sprintf('total elements: %s', $result->getResponseData()->getPagination()->getTotal()) . PHP_EOL); -// print(sprintf('next item: %s', $result->getResponseData()->getPagination()->getNextItem()) . PHP_EOL); -// - - // ------------------------------------------------------------------------------ - // пока не делаем, т.к. нет понимания как будет использоваться в клиентском коде - // стратегия (без подсчёта) (-1) - // 1. делаем первую выборку - // 2. проверяем условия достижения окончания ( - // !!!! при этом необходимо: - // - отсортировать записи по ID и добавить в фильтр условие ID > значения последнего элемента и с каждым шагом увеличивать его значение. - // - значение же последнего элемента брать из последнего значения полученного результата. - // - условием остановки импорта будет пустой ответ, или то, что в ответе элементов меньше 50. - // продумать кейсы: (выборки элементов), передача \ чтение результатов с автоподстановкой и т.д - - } catch (\Throwable $exception) { print(sprintf('ошибка: %s', $exception->getMessage()) . PHP_EOL); print(sprintf('тип: %s', get_class($exception)) . PHP_EOL); @@ -103,4 +69,3 @@ - From ee82785b63dc0862f46d5b0f0a9ef93065178d63 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 14 Dec 2020 00:16:00 +0300 Subject: [PATCH 178/647] add examples --- .../core/batch-query-iterable-read-examp.php | 4 +- .../core/batch-query-iterable-write-examp.php | 42 ++++--------------- 2 files changed, 12 insertions(+), 34 deletions(-) diff --git a/examples/core/batch-query-iterable-read-examp.php b/examples/core/batch-query-iterable-read-examp.php index ca6eda18..147a4b0b 100644 --- a/examples/core/batch-query-iterable-read-examp.php +++ b/examples/core/batch-query-iterable-read-examp.php @@ -17,7 +17,9 @@ $core = (new \Bitrix24\SDK\Core\CoreBuilder()) ->withLogger($log) - ->withWebhookUrl('') + // INSERT YOUR WEBHOOK HERE + ->withWebhookUrl('https://') + // INSERT YOUR WEBHOOK HERE ->build(); $dealsService = new \Bitrix24\SDK\Services\CRM\Deals\Service\Deals($core, $log); diff --git a/examples/core/batch-query-iterable-write-examp.php b/examples/core/batch-query-iterable-write-examp.php index cf653f79..8ffdbd20 100644 --- a/examples/core/batch-query-iterable-write-examp.php +++ b/examples/core/batch-query-iterable-write-examp.php @@ -2,33 +2,23 @@ declare(strict_types=1); require_once dirname(__DIR__, 2) . '/vendor/autoload.php'; -require_once 'vendor/autoload.php'; use Monolog\Handler\StreamHandler; use Monolog\Logger; -use Symfony\Component\HttpClient\HttpClient; $log = new Logger('name'); -$log->pushHandler(new StreamHandler('b24-api-client-debug.log', Logger::DEBUG)); +$log->pushHandler(new StreamHandler('examples/logs/b24-api-client.log', Logger::DEBUG)); $log->pushProcessor(new \Monolog\Processor\MemoryUsageProcessor(true, true)); -$client = HttpClient::create(['http_version' => '2.0']); -//$httpClient = new \Symfony\Component\HttpClient\TraceableHttpClient($client); -//$httpClient->setLogger($log); - -// $httpClient = HttpClient::create(); - - -$credentials = Bitrix24\SDK\Core\Credentials\Credentials::createForWebHook( - new \Bitrix24\SDK\Core\Credentials\WebhookUrl('https://') -); - try { - $apiClient = new \Bitrix24\SDK\Core\ApiClient($credentials, $httpClient, $log); - $ed = new \Symfony\Component\EventDispatcher\EventDispatcher(); - $core = new \Bitrix24\SDK\Core\Core($apiClient, $ed, $log); - - $arraySize = 10000; + $core = (new \Bitrix24\SDK\Core\CoreBuilder()) + ->withLogger($log) + // INSERT YOUR WEBHOOK HERE + ->withWebhookUrl('https://') + // INSERT YOUR WEBHOOK HERE + ->build(); + + $arraySize = 100; print(sprintf('Prepare raw data example...') . PHP_EOL); $rawDeals = []; for ($i = 0; $i < $arraySize; $i++) { @@ -74,20 +64,6 @@ } $timeEnd = microtime(true); print(sprintf('batch query duration: %s seconds', round($timeEnd - $timeStart, 2)) . PHP_EOL . PHP_EOL); - // todo режим добавление с чтением - - -// сравниваем с последовательным добавлением сделок -// print(sprintf('compare with single query mode...') . PHP_EOL); -// $dealsService = new \Bitrix24\SDK\Services\CRM\Deals\Service\Deals($core, $log); -// $timeStart = microtime(true); -// foreach ($rawDeals as $cnt => $deal) { -// $dealId = $dealsService->add($deal); -// print(sprintf('%s | deal id - %s', $cnt, $dealId) . PHP_EOL); -// } -// $timeEnd = microtime(true); -// print(sprintf(' single query mode time: %s', $timeEnd - $timeStart) . PHP_EOL); - } catch (\Throwable $exception) { print(sprintf('ошибка: %s', $exception->getMessage()) . PHP_EOL); print(sprintf('тип: %s', get_class($exception)) . PHP_EOL); From b9096b3959897db51de18ee5414d4e69b5ef02d5 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 14 Dec 2020 00:20:02 +0300 Subject: [PATCH 179/647] bump php version to 7.4 and add batch query documentation --- .gitignore | 5 +- README.md | 4 + composer.json | 12 +- docs/RU/Core/Batch/batch-read-mode.md | 122 ++++++ phpstan.neon | 7 + tools/.env | 3 + .../CRM/Contacts/GenerateContactsCommand.php | 182 +++++++++ tools/PerformanceBenchmarks/ListCommand.php | 367 ++++++++++++++++++ tools/bin/console | 53 +++ 9 files changed, 753 insertions(+), 2 deletions(-) create mode 100644 docs/RU/Core/Batch/batch-read-mode.md create mode 100644 phpstan.neon create mode 100644 tools/.env create mode 100644 tools/DemoDataGenerators/CRM/Contacts/GenerateContactsCommand.php create mode 100644 tools/PerformanceBenchmarks/ListCommand.php create mode 100644 tools/bin/console diff --git a/.gitignore b/.gitignore index f62d901e..0cff48d7 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,7 @@ vendor composer.phar composer.lock -.phpunit.result.cache \ No newline at end of file +.phpunit.result.cache +tools/.env.local +tools/logs +examples/logs \ No newline at end of file diff --git a/README.md b/README.md index ecdbc237..396da4f8 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,10 @@ add low-level tools to devs: API - level features - ~~3.1 auto renew access tokens~~ - 3.2 batch queries (work in progress) +- ~~3.2.1 read~~ +- ~~3.2.2 write~~ +- 3.2.3 read + write +- 3.2.4 read without count flag - 3.3 list queries with «start=-1» support - 3.4 offline queues - 3.5 add change domain URL support diff --git a/composer.json b/composer.json index f1877fa1..725e9b28 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ } ], "require": { - "php": ">=7.3", + "php": "7.4.*", "ext-json": "*", "ext-curl": "*", "psr/log": "1.1.3", @@ -27,6 +27,11 @@ "ramsey/uuid": "^3.9.3" }, "require-dev": { + "monolog/monolog": "2.1.*", + "symfony/console": "5.2.*", + "symfony/dotenv": "5.2.*", + "symfony/debug-bundle": "5.2.*", + "phpstan/phpstan": "0.12.59", "phpunit/phpunit": "9.3.*", "roave/security-advisories": "dev-master" }, @@ -35,6 +40,11 @@ "Bitrix24\\SDK\\": "src" } }, + "autoload-dev": { + "psr-4": { + "Bitrix24\\SDK\\Tools\\": "tools" + } + }, "scripts": { "test": [ "phpunit --colors=always --verbose" diff --git a/docs/RU/Core/Batch/batch-read-mode.md b/docs/RU/Core/Batch/batch-read-mode.md new file mode 100644 index 00000000..dc81e663 --- /dev/null +++ b/docs/RU/Core/Batch/batch-read-mode.md @@ -0,0 +1,122 @@ +# 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.1724 | 1.9875 | 2.3136 +сортировка, без подсчёта количества элементов в выборке | 0.1173 | 1.3289 | 1.476 +сортировка по умолчанию, подсчёт количества элементов в выборке | 0.0936 | 0.926 | 1.0272 +сортировка по умолчанию, без подсчёта количества элементов в выборке | 0.0362 | 0.2701 | 0.2688 + +### Чтение 6000 элементов — отдельные поля \ вся сущность \ вся сущность + пользовательские поля + +В данном примере используются batch-запросы, которые выбирают данные чанками по 2500, 2500 и 1000 элементов. Сами батч запросы реализуются +сервисом `Bitrix24\SDK\Core\Batch` Время — секунды, округление до 4 знаков. + +Режим | отдельные поля | вся сущность | вся сущность + UF_* +--- | --- | --- | --- +сортировка, подсчёт количества элементов в выборке | 17.8018 | 239.8081 | 274.9921 +сортировка, без подсчёта количества элементов в выборке | **not implemented** | **not implemented** | **not implemented** +сортировка по умолчанию, подсчёт количества элементов в выборке | 8.2121 | 110.0122 | 125.7331 +сортировка по умолчанию, без подсчёта количества элементов в выборке | **not implemented** | **not implemented** | **not implemented** + +## Подготовка тестового окружения + +Сгенерируйте тестовые контакты для вашего dev-окружения используя CLI-команду из папки tools +`generate:contacts` + +## Комментарии + +1. В текущей версии статьи в портале было 100к элементов в сущности, эта ситуация характерна для небольшого количества порталов +2. Замеры производились когда на портале отсутствовала операционная нагрузка характерная для рабочего дня +3. По возможности старайтесь избегать выборки всех данных +4. Сортировка данных при больших выборках тоже слишком дорогая операция +5. В roadmap SDK будет добавлена задача на поддержку batch-запросов в режиме «отключенный подсчёт количества» элементов, сейчас там + указано **not implemented** +6. Замеры будут проведены для кейсов от 10к до 200к элементов с шагом 10к элементов. +7. В коробочной версии Битрикс24 показатели могут существенно отличаться diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 00000000..7aef7b70 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,7 @@ +parameters: + level: 5 + paths: + - src/ + - tests/ + bootstrapFiles: + - tests/bootstrap.php \ No newline at end of file diff --git a/tools/.env b/tools/.env new file mode 100644 index 00000000..1581fc9b --- /dev/null +++ b/tools/.env @@ -0,0 +1,3 @@ +APP_ENV=dev +LOGS_FILE=tools/logs/cli.log +LOGS_LEVEL=100 \ No newline at end of file diff --git a/tools/DemoDataGenerators/CRM/Contacts/GenerateContactsCommand.php b/tools/DemoDataGenerators/CRM/Contacts/GenerateContactsCommand.php new file mode 100644 index 00000000..baf04d77 --- /dev/null +++ b/tools/DemoDataGenerators/CRM/Contacts/GenerateContactsCommand.php @@ -0,0 +1,182 @@ +logger = $logger; + parent::__construct(); + } + + /** + * настройки + */ + protected function configure(): void + { + $this + ->setDescription('generate contacts') + ->setHelp('generate demo-data contacts in CRM') + ->addOption( + self::WEBHOOK_URL, + null, + InputOption::VALUE_REQUIRED, + 'bitrix24 incoming webhook', + '' + ) + ->addOption( + self::CONTACTS_COUNT, + null, + InputOption::VALUE_REQUIRED, + 'contacts count', + 1 + ); + } + + /** + * @param InputInterface $input + * @param OutputInterface $output + * + * @return int + */ + protected function execute(InputInterface $input, OutputInterface $output): int + { + $this->logger->debug('GenerateContactsCommand.start'); + + $contactsCount = (int)$input->getOption(self::CONTACTS_COUNT); + $b24Webhook = (string)$input->getOption(self::WEBHOOK_URL); + $io = new SymfonyStyle($input, $output); + + $output->writeln( + [ + 'Generate contacts in CRM', + '========================', + sprintf('webhook url: %s', $b24Webhook), + sprintf('try to add contacts: %s', $contactsCount), + ] + ); + + try { + $contacts = $this->generateContacts($contactsCount); + + $core = (new \Bitrix24\SDK\Core\CoreBuilder()) + ->withLogger($this->logger) + ->withWebhookUrl($b24Webhook) + ->build(); + + $countResult = $core->call('crm.contact.list'); + $output->writeln(sprintf('contacts total count: %s', $countResult->getResponseData()->getPagination()->getTotal())); + + $batch = new \Bitrix24\SDK\Core\Batch($core, $this->logger); + foreach ($contacts as $cnt => $contact) { + $batch->addCommand('crm.contact.add', $contact); + } + $io->section('start adding contacts…'); + + $timeStart = microtime(true); + foreach ($batch->getTraversable(true) as $queryCnt => $queryResultData) { + /** + * @var $queryResultData ResponseData + */ + $io->writeln( + [ + sprintf( + '%s Mb |%s of %s | contact id: %s', + round(memory_get_peak_usage(true) / 1024 / 1024, 2), + $queryCnt + 1, + $contactsCount, + $queryResultData->getResult()->getResultData()[0] + ), + ] + ); + } + $timeEnd = microtime(true); + $io->writeln(sprintf('batch query duration: %s seconds', round($timeEnd - $timeStart, 2)) . PHP_EOL . PHP_EOL); + $io->success('contacts added'); + } catch (BaseException $exception) { + $io = new SymfonyStyle($input, $output); + $io->caution('Bitrix24 error'); + $io->text( + [ + sprintf('%s', $exception->getMessage()), + ] + ); + } catch (\Throwable $exception) { + $io = new SymfonyStyle($input, $output); + $io->caution('unknown error'); + $io->text( + [ + sprintf('%s', $exception->getMessage()), + ] + ); + } + $this->logger->debug('GenerateContactsCommand.finish'); + + return 0; + } + + /** + * @param int $contactsCount + * + * @return array $contacts + * @throws \Exception + */ + protected function generateContacts(int $contactsCount): array + { + $contacts = []; + for ($i = 0; $i < $contactsCount; $i++) { + $contacts[] = [ + 'fields' => [ + 'NAME' => sprintf('name_%s', $i), + 'LAST_NAME' => sprintf('last_%s', $i), + 'SECOND_NAME' => sprintf('second_%s', $i), + 'PHONE' => [ + ['VALUE' => sprintf('+7978%s', random_int(1000000, 9999999)), 'VALUE_TYPE' => 'MOBILE'], + ], + 'EMAIL' => [ + ['VALUE' => sprintf('test-%s@gmail.com', random_int(1000000, 9999999)), 'VALUE_TYPE' => 'WORK'], + ], + ], + ]; + } + + return $contacts; + } +} + diff --git a/tools/PerformanceBenchmarks/ListCommand.php b/tools/PerformanceBenchmarks/ListCommand.php new file mode 100644 index 00000000..c7548d2c --- /dev/null +++ b/tools/PerformanceBenchmarks/ListCommand.php @@ -0,0 +1,367 @@ + '1. ordered, count total elements', + 'order_without_count' => '2. ordered, without count total elements', + 'without_order_count' => '3. default order, count total elements', + 'without_order_without_count' => '4. default order, without count total elements', + ]; + protected array $selectMode = [ + 'partial' => ['ID', 'NAME', 'LAST_NAME', 'DATE_CREATE', 'PHONE', 'EMAIL'], + 'system' => ['*', 'PHONE', 'EMAIL', 'IM'], + 'all' => ['*', 'PHONE', 'EMAIL', 'IM', 'UF_*'], + ]; + + /** + * ListCommand constructor. + * + * @param LoggerInterface $logger + */ + public function __construct(LoggerInterface $logger) + { + // best practices recommend to call the parent constructor first and + // then set your own properties. That wouldn't work in this case + // because configure() needs the properties set in this constructor + $this->logger = $logger; + parent::__construct(); + } + + /** + * настройки + */ + protected function configure(): void + { + $this + ->setDescription('performance benchmark for *.list method') + ->setHelp('performance benchmark for *.list method with simple or batch mode if need read more than 50 elements') + ->addOption( + self::WEBHOOK_URL, + null, + InputOption::VALUE_REQUIRED, + 'bitrix24 incoming webhook', + '' + ) + ->addOption( + self::ROUNDS_COUNT, + null, + InputOption::VALUE_REQUIRED, + 'benchmark rounds count', + 3 + ) + ->addOption( + self::SELECT_FIELDS_MODE, + null, + InputOption::VALUE_REQUIRED, + 'select fields mode (partial | system | all)', + 'all' + ) + ->addOption( + self::ELEMENTS_COUNT, + null, + InputOption::VALUE_REQUIRED, + 'read elements count', + 50 + ); + } + + /** + * @param InputInterface $input + * @param OutputInterface $output + * + * @return int + */ + protected function execute(InputInterface $input, OutputInterface $output): int + { + $this->logger->debug('ListCommand.start'); + + $b24Webhook = (string)$input->getOption(self::WEBHOOK_URL); + $selectFieldsMode = strtolower((string)$input->getOption(self::SELECT_FIELDS_MODE)); + $elementsCount = (int)$input->getOption(self::ELEMENTS_COUNT); + $roundsCount = (int)$input->getOption(self::ROUNDS_COUNT); + + $isUseBatchMode = false; + if ($elementsCount > 50) { + $isUseBatchMode = true; + } + + $io = new SymfonyStyle($input, $output); + try { + $output->writeln( + [ + 'PerformanceBenchmark for crm.contact.list method', + '================================================', + sprintf('webhook url: %s', $b24Webhook), + sprintf('elements count: %s', $elementsCount), + sprintf('is use batch read mode: %s', $isUseBatchMode ? 'yes' : 'no'), + sprintf('benchmark rounds count: %s', $roundsCount), + sprintf('select fields mode: %s', $selectFieldsMode), + '', + 'fields select modes:', + '- partial: ID, NAME, LAST_NAME, DATE_CREATE, PHONE, EMAIL, IM', + '- system: *, PHONE, EMAIL, IM', + '- all: *, PHONE, EMAIL, IM, UF_*', + ] + ); + + $this->core = (new \Bitrix24\SDK\Core\CoreBuilder()) + ->withLogger($this->logger) + ->withWebhookUrl($b24Webhook) + ->build(); + + $countResult = $this->core->call('crm.contact.list'); + $output->writeln(['======', '']); + $output->writeln(sprintf('contacts total count: %s', $countResult->getResponseData()->getPagination()->getTotal())); + + + $order = ['DATE_CREATE' => 'ASC']; + $filter = ['>ID' => 1]; + if (!array_key_exists($selectFieldsMode, $this->selectMode)) { + throw new \InvalidArgumentException(sprintf('invalid select mode %s', $selectFieldsMode)); + } + $select = $this->selectMode[$selectFieldsMode]; + + + if ($isUseBatchMode) { + $output->writeln(sprintf('crm.contact.list - get %s elements in batch mode...', $elementsCount)); + + $result = $this->batchList($output, $order, $filter, $select, $elementsCount); + + $output->writeln(''); + $table = new Table($output); + $table->setHeaders(['Mode', 'Time']); + $table->addRow([$this->benchmarkItems['order_count'], round($result['order_count'], self::TIME_PRECISION)]); + $table->addRow([$this->benchmarkItems['order_without_count'], 'not implemented']); + $table->addRow([$this->benchmarkItems['without_order_count'], round($result['without_order_count'], self::TIME_PRECISION)]); + $table->addRow([$this->benchmarkItems['without_order_without_count'], 'not implemented']); + $table->render(); + } else { + $output->writeln('crm.contact.list - get first 50 elements...'); + + // creates a new progress bar (50 units) + $progressBar = new ProgressBar($output, $roundsCount); + $progressBar->start(); + + $totalStat = []; + for ($i = 0; $i < $roundsCount; $i++) { + $totalStat[] = $this->simpleList($order, $filter, $select); + $progressBar->advance(); + } + $progressBar->finish(); + $output->writeln(''); + $table = new Table($output); + $table + ->setHeaders(['Mode', 'Time']); + foreach ($this->benchmarkItems as $code => $description) { + // calculate average + $roundsStat = array_column($totalStat, $code); + $value = round(array_sum($roundsStat) / count($roundsStat), self::TIME_PRECISION); + $table->addRow( + [ + $this->benchmarkItems[$code], + $value, + ] + ); + } + $table->render(); + } + $io->success('benchmark finished'); + } catch (BaseException $exception) { + $io->caution('Bitrix24 error'); + $io->text( + [ + sprintf('%s', $exception->getMessage()), + ] + ); + } catch (\Throwable $exception) { + $io->caution('fatal error'); + $io->text( + [ + $exception->getMessage(), + $exception->getTraceAsString(), + ] + ); + } + $this->logger->debug('ListCommand.start.finish'); + + return self::SUCCESS; + } + + /** + * @param OutputInterface $output + * @param array $order + * @param array $filter + * @param array $select + * @param int $elementsCount + * + * @return array + * @throws BaseException + * @throws ClientExceptionInterface + * @throws RedirectionExceptionInterface + * @throws ServerExceptionInterface + * @throws TransportException + * @throws TransportExceptionInterface + */ + protected function batchList(OutputInterface $output, array $order, array $filter, array $select, int $elementsCount): array + { + $result = []; + + $output->writeln(['', '1. batch requests - ordered, count total elements...', '']); + $result['order_count'] = $this->getBatchQueryTime($output, $order, $filter, $select, $elementsCount); + + $output->writeln(['', '2. batch requests - ordered, without count total elements | NOT IMPLEMENTED', '']); + $result['order_without_count'] = null; + + $output->writeln(['', '3. batch requests - default order, count total elements...', '']); + $result['without_order_count'] = $this->getBatchQueryTime($output, [], $filter, $select, $elementsCount); + + $output->writeln(['', '4. batch requests - default order, without count total elements | NOT IMPLEMENTED', '']); + $result['without_order_without_count'] = null; + + return $result; + } + + /** + * @param OutputInterface $output + * @param array $order + * @param array $filter + * @param array $select + * @param int $elementsCount + * + * @return float + * @throws BaseException + * @throws ClientExceptionInterface + * @throws RedirectionExceptionInterface + * @throws ServerExceptionInterface + * @throws TransportException + * @throws TransportExceptionInterface + */ + protected function getBatchQueryTime(OutputInterface $output, array $order, array $filter, array $select, int $elementsCount): float + { + $timeStart = microtime(true); + $batch = new \Bitrix24\SDK\Core\Batch($this->core, $this->logger); + $progressBar = new ProgressBar($output, $elementsCount); + $progressBar->setFormat("%current%/%max% [%bar%] %percent:3s%%\n %memory:6s% | %status%\n"); + $progressBar->setMessage('wait first batch query result...', 'status'); + $progressBar->start(); + + $elementsFromBatchCount = 0; + foreach ($batch->getTraversableList('crm.contact.list', $order, $filter, $select, $elementsCount) as $queryItem) { + $curTime = microtime(true); + $elementsFromBatchCount++; + $progressBar->advance(); + + $progressBar->setMessage( + sprintf( + ' %s sec |# %s | %s - %s ', + round($curTime - $timeStart, 2), + $elementsFromBatchCount, + $queryItem['ID'], + $queryItem['NAME'] + ), + 'status' + ); + } + $timeEnd = microtime(true); + $progressBar->finish(); + + return $timeEnd - $timeStart; + } + + /** + * @param array $order + * @param array $filter + * @param array $select + * + * @return array + * @throws BaseException + * @throws TransportException + * @throws ClientExceptionInterface + * @throws RedirectionExceptionInterface + * @throws ServerExceptionInterface + * @throws TransportExceptionInterface + */ + protected function simpleList(array $order, array $filter, array $select): array + { + $default = $this->core->call( + 'crm.contact.list', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => 1, + ] + ); + $orderAndNoCount = $this->core->call( + 'crm.contact.list', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => -1, + ] + ); + $noOrderAndCount = $this->core->call( + 'crm.contact.list', + [ + 'order' => [], + 'filter' => $filter, + 'select' => $select, + 'start' => 1, + ] + ); + $noOrderAndNoCount = $this->core->call( + 'crm.contact.list', + [ + 'order' => [], + 'filter' => $filter, + 'select' => $select, + 'start' => -1, + ] + ); + + return [ + 'order_count' => $default->getResponseData()->getTime()->getDuration(), + 'order_without_count' => $orderAndNoCount->getResponseData()->getTime()->getDuration(), + 'without_order_count' => $noOrderAndCount->getResponseData()->getTime()->getDuration(), + 'without_order_without_count' => $noOrderAndNoCount->getResponseData()->getTime()->getDuration(), + ]; + } +} \ No newline at end of file diff --git a/tools/bin/console b/tools/bin/console new file mode 100644 index 00000000..df7d24ce --- /dev/null +++ b/tools/bin/console @@ -0,0 +1,53 @@ +#!/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(dirname(__DIR__) . '/.env'); + +if ($_SERVER['APP_DEBUG']) { + umask(0000); + + if (class_exists( + Debug::class + )) { + Debug::enable(); + } +} + +$log = new Logger('demo-data-generator'); +$log->pushHandler(new StreamHandler($_ENV['LOGS_FILE'], (int)$_ENV['LOGS_LEVEL'])); +$log->pushProcessor(new \Monolog\Processor\MemoryUsageProcessor(true, true)); + +$application = new Application(); +$application->add(new GenerateContactsCommand($log)); +$application->add(new ListCommand($log)); +$application->run($input); \ No newline at end of file From 8e31681e4e507ae0a717f45946c9bcc2abd4b12f Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 14 Dec 2020 00:22:39 +0300 Subject: [PATCH 180/647] update documentation --- docs/RU/documentation.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/docs/RU/documentation.md b/docs/RU/documentation.md index f9c8855a..4de77c25 100644 --- a/docs/RU/documentation.md +++ b/docs/RU/documentation.md @@ -1,20 +1,24 @@ -Документация по работе с bitrix24-php-sdk +Документация по работе с bitrix24-php-sdk ============================================= ## Авторизация на портале + - с использованием [входящих веб-хуков](Core/Auth/auth.md) - с использованием [OAuth 2.0 токенов](Core/Auth/auth.md#подключение-к-битрикс24-с-использованием-oauth-20) ## Возвращаемые результаты ApiClient -- унифицированный объект [Response](Core/Response/response.md) + +- унифицированный объект [Response](Core/Response/response.md) ## Обработка событий -При работе с SDK могут возникать события, которые требуется обработать в клиентском коде. -Библиотека позволяет подписаться на эти события с помощью компонента `EventDispatcher` + +При работе с SDK могут возникать события, которые требуется обработать в клиентском коде. Библиотека позволяет подписаться на эти события с +помощью компонента `EventDispatcher` Список [событий](Core/Events/events.md), на которые можно подписаться. ## Отправка запросов в пакетном режиме — batch -- работа с батч-запросами (wip) -- получение данных по фильтру -- получение больших объёмов (start=-1) +- [получение данных](Core/Batch/batch-read-mode.md) в batch-режиме +- запись данных в batch-режиме +- смешанный режим работы + \ No newline at end of file From 8a9d0856fbd94b8400764a9785138bc8f41e6a80 Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 18 Dec 2020 00:07:19 +0300 Subject: [PATCH 181/647] add service builders and example services --- docs/RU/documentation.md | 56 ++++- examples/services/service-examp.php | 41 ++++ src/Core/Batch.php | 32 +-- src/Core/Contracts/BatchInterface.php | 31 +++ src/Core/Contracts/CoreInterface.php | 27 +++ src/Core/Core.php | 11 +- src/Core/CoreBuilder.php | 5 +- src/Services/AbstractService.php | 20 +- src/Services/AbstractServiceBuilder.php | 37 ++++ src/Services/CRM/CRMServiceBuilder.php | 80 +++++++ .../CRM/Contacts/Service/Contacts.php | 206 ++++++++++++++++++ .../CRM/Deals/Service/DealCategory.php | 46 ++++ .../CRM/Deals/Service/DealProductRows.php | 79 +++++++ src/Services/CRM/Deals/Service/Deals.php | 67 ++++-- .../CRM/Products/Service/Products.php | 104 +++++++++ src/Services/IM/IMServiceBuilder.php | 28 +++ src/Services/IM/Service/IM.php | 83 +++++++ src/Services/Main.php | 43 ---- src/Services/Main/MainServiceBuilder.php | 28 +++ src/Services/Main/Service/Main.php | 153 +++++++++++++ src/Services/ServiceBuilder.php | 53 +++++ 21 files changed, 1125 insertions(+), 105 deletions(-) create mode 100644 examples/services/service-examp.php create mode 100644 src/Core/Contracts/BatchInterface.php create mode 100644 src/Core/Contracts/CoreInterface.php create mode 100644 src/Services/AbstractServiceBuilder.php create mode 100644 src/Services/CRM/CRMServiceBuilder.php create mode 100644 src/Services/CRM/Contacts/Service/Contacts.php create mode 100644 src/Services/CRM/Deals/Service/DealCategory.php create mode 100644 src/Services/CRM/Deals/Service/DealProductRows.php create mode 100644 src/Services/CRM/Products/Service/Products.php create mode 100644 src/Services/IM/IMServiceBuilder.php create mode 100644 src/Services/IM/Service/IM.php delete mode 100644 src/Services/Main.php create mode 100644 src/Services/Main/MainServiceBuilder.php create mode 100644 src/Services/Main/Service/Main.php create mode 100644 src/Services/ServiceBuilder.php diff --git a/docs/RU/documentation.md b/docs/RU/documentation.md index 4de77c25..e7d9b782 100644 --- a/docs/RU/documentation.md +++ b/docs/RU/documentation.md @@ -17,8 +17,62 @@ Список [событий](Core/Events/events.md), на которые можно подписаться. ## Отправка запросов в пакетном режиме — batch + - [получение данных](Core/Batch/batch-read-mode.md) в batch-режиме - запись данных в batch-режиме - смешанный режим работы - \ No newline at end of file +## Сервисы + +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` \ No newline at end of file diff --git a/examples/services/service-examp.php b/examples/services/service-examp.php new file mode 100644 index 00000000..f048618b --- /dev/null +++ b/examples/services/service-examp.php @@ -0,0 +1,41 @@ +pushHandler(new StreamHandler('examples/logs/b24-api-client.log', Logger::DEBUG)); +$log->pushProcessor(new \Monolog\Processor\MemoryUsageProcessor(true, true)); +$log->pushProcessor(new \Monolog\Processor\IntrospectionProcessor()); +$log->debug('=============================================================='); + +try { + print('получаем данные:' . PHP_EOL); + + // сконфигурировали SDK + $core = (new \Bitrix24\SDK\Core\CoreBuilder()) + ->withLogger($log) + // INSERT YOUR WEBHOOK HERE + ->withWebhookUrl('') + // INSERT YOUR WEBHOOK HERE + ->build(); + $batch = new \Bitrix24\SDK\Core\Batch($core, $log); + $serviceBuilder = new ServiceBuilder($core, $batch, $log); + + // получили сервис по работе с контактами из модуля CRM + // именно сервис предоставляет CRUD+ api по работе с сущностью + $contactService = $serviceBuilder->getCRMScope()->contacts(); + + // получили первые 50 контактов вызвав метод crm.contact.list + $contacts = $contactService->list([], [], [], 0); + var_dump($contacts->getResponseData()->getResult()->getResultData()); + var_dump($contacts->getResponseData()->getPagination()->getTotal()); +} catch (\Throwable $exception) { + print(sprintf('ошибка: %s', $exception->getMessage()) . PHP_EOL); + print(sprintf('тип: %s', get_class($exception)) . PHP_EOL); + print(sprintf('trace: %s', $exception->getTraceAsString()) . PHP_EOL); +} \ No newline at end of file diff --git a/src/Core/Batch.php b/src/Core/Batch.php index 19147fc6..1570d4e2 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -6,6 +6,8 @@ use Bitrix24\SDK\Core\Commands\Command; use Bitrix24\SDK\Core\Commands\CommandCollection; +use Bitrix24\SDK\Core\Contracts\BatchInterface; +use Bitrix24\SDK\Core\Contracts\CoreInterface; use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Response\DTO\Pagination; use Bitrix24\SDK\Core\Response\DTO\ResponseData; @@ -20,35 +22,23 @@ * * @package Bitrix24\SDK\Core */ -class Batch +class Batch implements BatchInterface { - /** - * @var Core - */ - private $coreService; - /** - * @var LoggerInterface - */ - private $log; - /** - * @var int - */ + private CoreInterface $core; + private LoggerInterface $log; protected const MAX_BATCH_PACKET_SIZE = 50; protected const MAX_ELEMENTS_IN_PAGE = 50; - /** - * @var CommandCollection - */ - protected $commands; + protected CommandCollection $commands; /** * Batch constructor. * - * @param Core $core + * @param CoreInterface $core * @param LoggerInterface $log */ - public function __construct(Core $core, LoggerInterface $log) + public function __construct(CoreInterface $core, LoggerInterface $log) { - $this->coreService = $core; + $this->core = $core; $this->log = $log; $this->commands = new CommandCollection(); } @@ -137,7 +127,7 @@ public function getTraversableList(string $apiMethod, array $order, array $filte $this->clearCommands(); // get total elements count - $firstResult = $this->coreService->call( + $firstResult = $this->core->call( $apiMethod, [ 'order' => $order, @@ -325,7 +315,7 @@ private function getTraversableBatchResults(bool $isHaltOnError): Generator ] ); // batch call - $batchResult = $this->coreService->call('batch', ['halt' => $isHaltOnError, 'cmd' => $batchQuery]); + $batchResult = $this->core->call('batch', ['halt' => $isHaltOnError, 'cmd' => $batchQuery]); // todo analyze batch result and halt on error $batchQueryCounter++; diff --git a/src/Core/Contracts/BatchInterface.php b/src/Core/Contracts/BatchInterface.php new file mode 100644 index 00000000..c9bee7a2 --- /dev/null +++ b/src/Core/Contracts/BatchInterface.php @@ -0,0 +1,31 @@ +webhookUrl !== null) { $this->credentials = Credentials::createForWebHook($this->webhookUrl); diff --git a/src/Services/AbstractService.php b/src/Services/AbstractService.php index 123ff4ad..5a505d58 100644 --- a/src/Services/AbstractService.php +++ b/src/Services/AbstractService.php @@ -4,7 +4,8 @@ namespace Bitrix24\SDK\Services; -use Bitrix24\SDK\Core\Core; +use Bitrix24\SDK\Core\Contracts\BatchInterface; +use Bitrix24\SDK\Core\Contracts\CoreInterface; use Psr\Log\LoggerInterface; /** @@ -14,24 +15,21 @@ */ abstract class AbstractService { - /** - * @var Core - */ - protected $core; - /** - * @var LoggerInterface - */ - protected $log; + protected BatchInterface $batch; + protected CoreInterface $core; + protected LoggerInterface $log; /** * AbstractService constructor. * - * @param Core $core + * @param CoreInterface $core + * @param BatchInterface $batch * @param LoggerInterface $log */ - public function __construct(Core $core, LoggerInterface $log) + public function __construct(CoreInterface $core, BatchInterface $batch, LoggerInterface $log) { $this->core = $core; + $this->batch = $batch; $this->log = $log; } } \ No newline at end of file diff --git a/src/Services/AbstractServiceBuilder.php b/src/Services/AbstractServiceBuilder.php new file mode 100644 index 00000000..ee7cac7d --- /dev/null +++ b/src/Services/AbstractServiceBuilder.php @@ -0,0 +1,37 @@ +core = $core; + $this->batch = $batch; + $this->log = $log; + } +} \ No newline at end of file diff --git a/src/Services/CRM/CRMServiceBuilder.php b/src/Services/CRM/CRMServiceBuilder.php new file mode 100644 index 00000000..523cabd5 --- /dev/null +++ b/src/Services/CRM/CRMServiceBuilder.php @@ -0,0 +1,80 @@ +serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new DealCategory($this->core, $this->batch, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + /** + * @return Deals + */ + public function deals(): Deals + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Deals($this->core, $this->batch, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + /** + * @return Products + */ + public function products(): Products + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Products($this->core, $this->batch, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + /** + * @return Contacts + */ + public function contacts(): Contacts + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Contacts($this->core, $this->batch, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + /** + * @return DealProductRows + */ + public function dealProductRows(): DealProductRows + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new DealProductRows($this->core, $this->batch, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Contacts/Service/Contacts.php b/src/Services/CRM/Contacts/Service/Contacts.php new file mode 100644 index 00000000..bcee785b --- /dev/null +++ b/src/Services/CRM/Contacts/Service/Contacts.php @@ -0,0 +1,206 @@ +log->debug( + 'getTraversableList.start', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'limit' => $limit, + ] + ); + + $result = $this->batch->getTraversableList('crm.contact.list', $order, $filter, $select, $limit); + + $this->log->debug('getTraversableList.finish'); + + return $result; + } + + /** + * @param array $fields + * @param array $params + * + * @return Response + * @throws BaseException + * @throws TransportException + */ + public function add(array $fields, array $params): Response + { + $this->log->debug( + 'add.start', + [ + 'fields' => $fields, + 'params' => $params, + ] + ); + + $result = $this->core->call( + 'crm.contact.add', + [ + 'fields' => $fields, + 'params' => $params, + ] + ); + + + $this->log->debug('add.finish'); + + return $result; + } + + /** + * @param int $contactId + * + * @return Response + * @throws BaseException + * @throws TransportException + */ + public function get(int $contactId): Response + { + $this->log->debug( + 'get.start', + [ + 'contactId' => $contactId, + ] + ); + $result = $this->core->call( + 'crm.contact.get', + [ + 'id' => $contactId, + ] + ); + + $this->log->debug('get.finish'); + + return $result; + } + + /** + * @param array $order + * @param array $filter + * @param array $select + * @param int $start + * + * @return Response + * @throws BaseException + * @throws TransportException + */ + public function list(array $order, array $filter, array $select, int $start): Response + { + $this->log->debug( + 'list.start', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $start, + ] + ); + + $result = $this->core->call( + 'crm.contact.list', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $start, + ] + ); + + $this->log->debug('list.finish'); + + return $result; + } + + /** + * @param int $contactId + * @param array $fields + * @param array $params + * + * @return Response + * @throws BaseException + * @throws TransportException + */ + public function update(int $contactId, array $fields, array $params): Response + { + $this->log->debug( + 'update.start', + [ + 'id' => $contactId, + 'fields' => $fields, + 'params' => $params, + ] + ); + + $result = $this->core->call( + 'crm.contact.update', + [ + 'id' => $contactId, + 'fields' => $fields, + 'params' => $params, + ] + ); + + $this->log->debug('update.finish'); + + return $result; + } + + /** + * @param int $contactId + * + * @return Response + * @throws BaseException + * @throws TransportException + */ + public function delete(int $contactId): Response + { + $this->log->debug( + 'delete.start', + [ + 'contactId' => $contactId, + ] + ); + + $result = $this->core->call( + 'crm.contact.delete', + [ + 'id' => $contactId, + ] + ); + + + $this->log->debug('delete.finish'); + + return $result; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deals/Service/DealCategory.php b/src/Services/CRM/Deals/Service/DealCategory.php new file mode 100644 index 00000000..8349731a --- /dev/null +++ b/src/Services/CRM/Deals/Service/DealCategory.php @@ -0,0 +1,46 @@ +log->debug( + 'add.start', + [ + 'fields' => $fields, + ] + ); + + $result = $this->core->call( + 'crm.dealcategory.add', + [ + 'fields' => $fields, + ] + ); + + $this->log->debug('add.finish'); + + return $result; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deals/Service/DealProductRows.php b/src/Services/CRM/Deals/Service/DealProductRows.php new file mode 100644 index 00000000..ef49b191 --- /dev/null +++ b/src/Services/CRM/Deals/Service/DealProductRows.php @@ -0,0 +1,79 @@ +log->debug( + 'get.start', + [ + 'dealId' => $dealId, + ] + ); + + $result = $this->core->call( + 'crm.deal.productrows.get', + [ + 'id' => $dealId, + ] + ); + + $this->log->debug('get.finish'); + + return $result; + } + + /** + * @param int $dealId + * @param array $productRows + * + * @return Response + * @throws BaseException + * @throws TransportException + */ + public function set(int $dealId, array $productRows): Response + { + $this->log->debug( + 'set.start', + [ + 'dealId' => $dealId, + 'productRows' => $productRows, + ] + ); + + + $result = $this->core->call( + 'crm.deal.productrows.set', + [ + 'id' => $dealId, + 'rows' => $productRows, + ] + ); + + + $this->log->debug('set.finish'); + + return $result; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deals/Service/Deals.php b/src/Services/CRM/Deals/Service/Deals.php index 7d8470fb..ff1088e6 100644 --- a/src/Services/CRM/Deals/Service/Deals.php +++ b/src/Services/CRM/Deals/Service/Deals.php @@ -4,8 +4,11 @@ namespace Bitrix24\SDK\Services\CRM\Deals\Service; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; use Bitrix24\SDK\Core\Response\Response; use Bitrix24\SDK\Services\AbstractService; +use Generator; /** * Class Deals @@ -14,6 +17,34 @@ */ class Deals extends AbstractService { + /** + * @param array $order + * @param array $filter + * @param array $select + * @param int|null $limit + * + * @return Generator + * @throws BaseException + */ + public function getTraversableList(array $order, array $filter, array $select, ?int $limit = null): Generator + { + $this->log->debug( + 'getTraversableList.start', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'limit' => $limit, + ] + ); + + $result = $this->batch->getTraversableList('crm.deal.list', $order, $filter, $select, $limit); + + $this->log->debug('getTraversableList.finish'); + + return $result; + } + /** * Get list of deal items. * @@ -56,18 +87,14 @@ public function list(array $order, array $filter, array $select, int $startItem * @param array $fields * @param array $params * - * @return int - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException - * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface - * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface - * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface - * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + * @return Response + * @throws BaseException + * @throws TransportException */ - public function add(array $fields, array $params = []): int + public function add(array $fields, array $params = []): Response { $this->log->debug( - 'deals.add.start', + 'add.start', [ 'fields' => $fields, 'params' => $params, @@ -82,26 +109,22 @@ public function add(array $fields, array $params = []): int ] ); - $this->log->debug('deals.add.finish'); + $this->log->debug('add.finish'); - return $result->getResponseData()->getResult()->getResultData()[0]; + return $result; } /** * @param int $id * - * @return array - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException - * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface - * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface - * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface - * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + * @return Response + * @throws BaseException + * @throws TransportException */ - public function get(int $id): array + public function get(int $id): Response { $this->log->debug( - 'deals.get.start', + 'get.start', [ 'id' => $id, ] @@ -109,8 +132,8 @@ public function get(int $id): array $response = $this->core->call('crm.deal.get', ['id' => $id]); - $this->log->debug('deals.get.finish'); + $this->log->debug('get.finish'); - return $response->getResponseData()->getResult()->getResultData(); + return $response; } } \ No newline at end of file diff --git a/src/Services/CRM/Products/Service/Products.php b/src/Services/CRM/Products/Service/Products.php new file mode 100644 index 00000000..1cd00c99 --- /dev/null +++ b/src/Services/CRM/Products/Service/Products.php @@ -0,0 +1,104 @@ +log->debug('add.start', ['fields' => $fields]); + + $result = $this->core->call( + 'crm.product.add', + [ + 'fields' => $fields, + ] + ); + + $this->log->debug('add.finish'); + + return $result; + } + + /** + * @param int $productId + * + * @return Response + * @throws BaseException + * @throws TransportException + */ + public function delete(int $productId): Response + { + $this->log->debug( + 'delete.start', + [ + 'id' => $productId, + ] + ); + + $result = $this->core->call( + 'crm.product.delete', + [ + 'id' => $productId, + ] + ); + + + $this->log->debug('delete.finish'); + + return $result; + } + + /** + * @param array $order + * @param array $filter + * @param array $select + * + * @return Response + * @throws BaseException + * @throws TransportException + */ + public function list(array $order, array $filter, array $select): Response + { + $this->log->debug( + 'list.start', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + ] + ); + + $result = $this->core->call( + 'crm.product.list', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + ] + ); + + $this->log->debug('list.finish'); + + return $result; + } +} \ No newline at end of file diff --git a/src/Services/IM/IMServiceBuilder.php b/src/Services/IM/IMServiceBuilder.php new file mode 100644 index 00000000..890c93a1 --- /dev/null +++ b/src/Services/IM/IMServiceBuilder.php @@ -0,0 +1,28 @@ +serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new IM($this->core, $this->batch, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } +} \ No newline at end of file diff --git a/src/Services/IM/Service/IM.php b/src/Services/IM/Service/IM.php new file mode 100644 index 00000000..bd1ca645 --- /dev/null +++ b/src/Services/IM/Service/IM.php @@ -0,0 +1,83 @@ +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/Main.php b/src/Services/Main.php deleted file mode 100644 index 6c3edac9..00000000 --- a/src/Services/Main.php +++ /dev/null @@ -1,43 +0,0 @@ -core->call('methods', [])->getResponseData()->getResult()->getResultData(); - } - - public function getAllMethods(): array - { - return $this->core->call('methods', ['full' => true])->getResponseData()->getResult()->getResultData(); - } - - public function getMethodsByScope(string $scopeName): array - { - return $this->core->call('methods', ['scope' => $scopeName])->getResponseData()->getResult()->getResultData(); - } - - public function getApplicationInfo(): array - { - return $this->core->call('app.info')->getResponseData()->getResult()->getResultData(); - } - - public function isCurrentUserHasAdminRights(): bool - { - return $this->core->call('user.admin')->getResponseData()->getResult()->getResultData()[0]; - } - - public function getUserProfile(): array - { - return $this->core->call('profile')->getResponseData()->getResult()->getResultData(); - } -} \ No newline at end of file diff --git a/src/Services/Main/MainServiceBuilder.php b/src/Services/Main/MainServiceBuilder.php new file mode 100644 index 00000000..db4033e5 --- /dev/null +++ b/src/Services/Main/MainServiceBuilder.php @@ -0,0 +1,28 @@ +serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Main($this->core, $this->batch, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } +} \ No newline at end of file diff --git a/src/Services/Main/Service/Main.php b/src/Services/Main/Service/Main.php new file mode 100644 index 00000000..e49f8bf3 --- /dev/null +++ b/src/Services/Main/Service/Main.php @@ -0,0 +1,153 @@ +log->debug('getCurrentScope.start'); + + $result = $this->core->call('scope'); + + $this->log->debug('getCurrentScope.finish'); + + return $result; + } + + /** + * @return Response + * @throws BaseException + * @throws TransportException + */ + public function getAvailableScope(): Response + { + $this->log->debug('getAvailableScope.start'); + + $result = $this->core->call('scope', ['full' => true]); + + $this->log->debug('getAvailableScope.finish'); + + return $result; + } + + /** + * @return Response + * @throws BaseException + * @throws TransportException + */ + public function getAvailableMethods(): Response + { + $this->log->debug('getAvailableMethods.start'); + + $result = $this->core->call('methods', []); + + $this->log->debug('getAvailableMethods.finish'); + + return $result; + } + + /** + * @return Response + * @throws BaseException + * @throws TransportException + */ + public function getAllMethods(): Response + { + $this->log->debug('getAllMethods.start'); + + $result = $this->core->call('methods', ['full' => true]); + + $this->log->debug('getAllMethods.finish'); + + return $result; + } + + /** + * @param string $scope + * + * @return Response + * @throws BaseException + * @throws TransportException + */ + public function getMethodsByScope(string $scope): Response + { + $this->log->debug( + 'getMethodsByScope.start', + [ + 'scope' => $scope, + ] + ); + + $result = $this->core->call('methods', ['scope' => $scope]); + + $this->log->debug('getMethodsByScope.finish'); + + return $result; + } + + /** + * @return Response + * @throws BaseException + * @throws TransportException + */ + public function getApplicationInfo(): Response + { + $this->log->debug('getApplicationInfo.start'); + + $result = $this->core->call('app.info'); + + $this->log->debug('getApplicationInfo.finish'); + + return $result; + } + + /** + * @return Response + * @throws BaseException + * @throws TransportException + */ + public function isCurrentUserHasAdminRights(): Response + { + $this->log->debug('isCurrentUserHasAdminRights.start'); + + $result = $this->core->call('user.admin'); + + $this->log->debug('isCurrentUserHasAdminRights.finish'); + + return $result; + } + + /** + * @return Response + * @throws BaseException + * @throws TransportException + */ + public function getUserProfile(): Response + { + $this->log->debug('getUserProfile.start'); + + $result = $this->core->call('profile'); + + $this->log->debug('getUserProfile.finish'); + + return $result; + } +} \ No newline at end of file diff --git a/src/Services/ServiceBuilder.php b/src/Services/ServiceBuilder.php new file mode 100644 index 00000000..86f05279 --- /dev/null +++ b/src/Services/ServiceBuilder.php @@ -0,0 +1,53 @@ +serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new CRMServiceBuilder($this->core, $this->batch, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + /** + * @return IMServiceBuilder + */ + public function getIMScope(): IMServiceBuilder + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new IMServiceBuilder($this->core, $this->batch, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + /** + * @return MainServiceBuilder + */ + public function getMainScope(): MainServiceBuilder + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new MainServiceBuilder($this->core, $this->batch, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } +} \ No newline at end of file From 8d5e698044f03b12500bb69b66352eef453983ec Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 18 Dec 2020 11:19:05 +0300 Subject: [PATCH 182/647] add deal category --- README.md | 29 ++- composer.json | 3 +- .../CRM/Deals/Service/DealCategory.php | 199 ++++++++++++++++++ 3 files changed, 224 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 396da4f8..5d8edaad 100644 --- a/README.md +++ b/README.md @@ -8,22 +8,24 @@ A powerful PHP library for the Bitrix24 REST API [Bitrix24 API documentation - English](https://training.bitrix24.com/rest_help/)
[Register new Bitrix24 account](https://www.bitrix24.ru/create.php?p=255670)
- ## SDK 2.0 core features -Bitrix24 auth features +Bitrix24 auth features + - ~~work with auth tokens~~ - ~~work with incoming webhooks~~ add low-level tools to devs: + - ~~2.1 events (token expired, domain url changed)~~ - 2.2 rate-limiter - wait for symfony/symfony#37471 - 2.3 RetryHttpClient - symfony/symfony#38182 API - level features -- ~~3.1 auto renew access tokens~~ + +- ~~3.1 auto renew access tokens~~ - 3.2 batch queries (work in progress) -- ~~3.2.1 read~~ +- ~~3.2.1 read~~ - ~~3.2.2 write~~ - 3.2.3 read + write - 3.2.4 read without count flag @@ -32,6 +34,7 @@ API - level features - 3.5 add change domain URL support Core DTO + - ~~Response~~ - ~~Scope~~ - ~~Time~~ @@ -40,12 +43,14 @@ Core DTO - ~~Pagination~~ ## SDK Documentation + - [Russian](/docs/RU/documentation.md) - [English](/docs/EN/documentation.md) ## Architecture ### Abstraction layers + ``` - http protocol - json data @@ -61,6 +66,7 @@ Core DTO ``` ### File Structure + ``` /Core ApiClient.php - default api-client, work on http abstraction layer, return - Symfony\Contracts\HttpClient\ResponseInterface @@ -76,14 +82,24 @@ Core DTO ``` ## Requirements + - php: >=7.4 - ext-json: * -- ext-curl: * +- ext-curl: * ## Example ## + ## Installation ## + Add `"mesilov/bitrix24-php-sdk": "2.x"` to `composer.json` of your application. Or clone repo to your project. +## Tests ## + +SDK test locate in folder `tests` and we have two test types + +- Unit: **fast**, in-memory tests without a network I\O +- Integration: **slow** tests with full lifecycle with test Bitrix24 portal via webhook + ## Submitting bugs and feature requests Bugs and feature request are tracked on [GitHub](https://github.com/mesilov/bitrix24-php-sdk/issues) @@ -98,10 +114,11 @@ Maxim Mesilov - -
See also the list of [contributors](https://github.com/mesilov/bitrix24-php-sdk/graphs/contributors) which participated in this project. ## Need custom Bitrix24 application? ## -email: +email: ## Русский ### Ключевые особенности + - сервисы возвращают структуры данных пригодные для работы внутри клиентского кода \ No newline at end of file diff --git a/composer.json b/composer.json index 725e9b28..4d3b7c15 100644 --- a/composer.json +++ b/composer.json @@ -42,7 +42,8 @@ }, "autoload-dev": { "psr-4": { - "Bitrix24\\SDK\\Tools\\": "tools" + "Bitrix24\\SDK\\Tools\\": "tools", + "Bitrix24\\SDK\\Tests\\": "tests" } }, "scripts": { diff --git a/src/Services/CRM/Deals/Service/DealCategory.php b/src/Services/CRM/Deals/Service/DealCategory.php index 8349731a..ee1e407f 100644 --- a/src/Services/CRM/Deals/Service/DealCategory.php +++ b/src/Services/CRM/Deals/Service/DealCategory.php @@ -43,4 +43,203 @@ public function add(array $fields): Response return $result; } + + /** + * @param int $categoryId + * + * @return Response + * @throws BaseException + * @throws TransportException + */ + public function delete(int $categoryId): Response + { + $this->log->debug( + 'delete.start', + [ + 'categoryId' => $categoryId, + ] + ); + + $result = $this->core->call( + 'crm.dealcategory.delete', + [ + 'id' => $categoryId, + ] + ); + + $this->log->debug('delete.finish'); + + return $result; + } + + /** + * @return Response + * @throws BaseException + * @throws TransportException + */ + public function fields(): Response + { + $this->log->debug('fields.start'); + + $result = $this->core->call('crm.dealcategory.fields'); + + $this->log->debug('fields.finish'); + + return $result; + } + + /** + * @param int $categoryId + * + * @return Response + * @throws BaseException + * @throws TransportException + */ + public function get(int $categoryId): Response + { + $this->log->debug( + 'get.start', + [ + 'categoryId' => $categoryId, + ] + ); + + $result = $this->core->call( + 'crm.dealcategory.get', + [ + 'id' => $categoryId, + ] + ); + + $this->log->debug('get.finish'); + + return $result; + } + + /** + * @return Response + * @throws BaseException + * @throws TransportException + */ + public function getDefaultCategorySettings(): Response + { + $this->log->debug(' getDefaultCategorySettings.start'); + + $result = $this->core->call('crm.dealcategory.default.get'); + + $this->log->debug(' getDefaultCategorySettings.finish'); + + return $result; + } + + /** + * @return Response + * @throws BaseException + * @throws TransportException + */ + public function setDefaultCategoryName(string $name): Response + { + $this->log->debug('setDefaultCategoryName.start'); + + $result = $this->core->call( + 'crm.dealcategory.default.set', + [ + 'name' => $name, + ] + ); + + $this->log->debug('setDefaultCategoryName.finish'); + + return $result; + } + + /** + * @param array $order + * @param array $filter + * @param array $select + * @param int $start + * + * @return Response + * @throws BaseException + * @throws TransportException + */ + public function list(array $order, array $filter, array $select, int $start): Response + { + $this->log->debug( + 'list.start', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $start, + ] + ); + + $result = $this->core->call( + 'crm.dealcategory.list', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $start, + ] + ); + + $this->log->debug('list.finish'); + + return $result; + } + + /** + * @param int $categoryId + * + * @return Response + * @throws BaseException + * @throws TransportException + */ + public function getStatus(int $categoryId): Response + { + $this->log->debug( + 'getStatus.start', + [ + 'categoryId' => $categoryId, + ] + ); + + $result = $this->core->call( + 'crm.dealcategory.status', + [ + 'id' => $categoryId, + ] + ); + + $this->log->debug('getStatus.finish'); + + return $result; + } + + /** + * @param int $categoryId + * @param array $fields + * + * @return Response + * @throws BaseException + * @throws TransportException + */ + public function update(int $categoryId, array $fields): Response + { + $this->log->debug( + 'update.start', + [ + 'categoryId' => $categoryId, + 'fields' => $fields, + ] + ); + + $result = $this->core->call('crm.dealcategory.update'); + + $this->log->debug('update.finish'); + + return $result; + } } \ No newline at end of file From cd79308754b07616d6af80d70778e9236e2f556d Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 18 Dec 2020 12:25:50 +0300 Subject: [PATCH 183/647] add deal categorystages --- src/Services/CRM/CRMServiceBuilder.php | 13 ++++++ .../CRM/Deals/Service/DealCategoryStages.php | 41 +++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 src/Services/CRM/Deals/Service/DealCategoryStages.php diff --git a/src/Services/CRM/CRMServiceBuilder.php b/src/Services/CRM/CRMServiceBuilder.php index 523cabd5..7127870d 100644 --- a/src/Services/CRM/CRMServiceBuilder.php +++ b/src/Services/CRM/CRMServiceBuilder.php @@ -7,6 +7,7 @@ use Bitrix24\SDK\Services\AbstractServiceBuilder; use Bitrix24\SDK\Services\CRM\Contacts\Service\Contacts; use Bitrix24\SDK\Services\CRM\Deals\Service\DealCategory; +use Bitrix24\SDK\Services\CRM\Deals\Service\DealCategoryStages; use Bitrix24\SDK\Services\CRM\Deals\Service\DealProductRows; use Bitrix24\SDK\Services\CRM\Deals\Service\Deals; use Bitrix24\SDK\Services\CRM\Products\Service\Products; @@ -77,4 +78,16 @@ public function dealProductRows(): DealProductRows return $this->serviceCache[__METHOD__]; } + + /** + * @return DealCategoryStages + */ + public function dealCategoryStages(): DealCategoryStages + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new DealCategoryStages($this->core, $this->batch, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } } \ No newline at end of file diff --git a/src/Services/CRM/Deals/Service/DealCategoryStages.php b/src/Services/CRM/Deals/Service/DealCategoryStages.php new file mode 100644 index 00000000..45bf77d4 --- /dev/null +++ b/src/Services/CRM/Deals/Service/DealCategoryStages.php @@ -0,0 +1,41 @@ +log->debug( + 'list.start', + [ + 'categoryId' => $categoryId, + ] + ); + + $result = $this->core->call('crm.dealcategory.stage.list'); + + $this->log->debug('list.finish'); + + return $result; + } +} \ No newline at end of file From a350382c6052ac2cedf5b35bccaf11631813e6a4 Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 18 Dec 2020 15:08:11 +0300 Subject: [PATCH 184/647] fix --- .../CRM/Deals/Service/DealCategoryStages.php | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/Services/CRM/Deals/Service/DealCategoryStages.php b/src/Services/CRM/Deals/Service/DealCategoryStages.php index 45bf77d4..789d93cf 100644 --- a/src/Services/CRM/Deals/Service/DealCategoryStages.php +++ b/src/Services/CRM/Deals/Service/DealCategoryStages.php @@ -25,17 +25,11 @@ class DealCategoryStages extends AbstractService */ public function list(int $categoryId): Response { - $this->log->debug( - 'list.start', + return $this->core->call( + 'crm.dealcategory.stage.list', [ - 'categoryId' => $categoryId, + 'id' => $categoryId, ] ); - - $result = $this->core->call('crm.dealcategory.stage.list'); - - $this->log->debug('list.finish'); - - return $result; } } \ No newline at end of file From d584f3a2ee923d3d0a021eaf3885075033b64c71 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 19 Dec 2020 19:19:15 +0300 Subject: [PATCH 185/647] add sdk description in russian --- README.md | 125 +++++++++++++++++- .../CRM/Products/Service/Products.php | 5 +- 2 files changed, 128 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5d8edaad..4f3fd787 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ A powerful PHP library for the Bitrix24 REST API [Bitrix24 API documentation - English](https://training.bitrix24.com/rest_help/)
[Register new Bitrix24 account](https://www.bitrix24.ru/create.php?p=255670)
+ ## SDK 2.0 core features Bitrix24 auth features @@ -118,7 +119,129 @@ See also the list of [contributors](https://github.com/mesilov/bitrix24-php-sdk/ email: ## Русский +### Принципы по которым ведётся разработка +- хороший DX (Developer Experience) +- хорошая документация +- производительность: + - SDK должно оказывать минимальное влияние на клиентский код + - должна быть возможность работать с большими объёмами данных с константным потреблением памяти + - SDK должно обеспечивать эффективную работу c API: поддержка батч-запросов +- работать на современном стеке технологий: + - использовать современные библиотеки для работы с сетью + - использовать фичи новых версий PHP +- надёжной: + - SDK покрыта тестами: unit, интеграционные, контрактные + - SDK имеет типовые примеры характерные для разных режимов работы и они оптимизированы по памяти \ быстродействию ### Ключевые особенности -- сервисы возвращают структуры данных пригодные для работы внутри клиентского кода \ No newline at end of file +### Слои SDK + +### Service – API-интерфейс для работы с конкретной сущностью + +Зона ответственности: + +- контракт на API-методы сущности + +Входящие данные: + +- сигнатура вызова конкретного API-метода + +Возвращаемый результат: + +- `Core\Response` (????) **к обсуждению** + +В зависимости от метода может быть разный возвращаемый результат: + +- результат выполнения операции типа bool +- идентификатор созданной сущности типа int +- сущность + пользовательские поля с префиксами UF_ типа array +- массив сущностей типа array +- пустой массив как результат пустого фильтра. + +Если возвращать `Core\Response`, то в клиентском коде будут проблемы: + +- длинные цепочки в клиентском коде для получения возвращаемого результата + +``` +// добавили сделку в Б24 +$dealId = $dealsService->add($newDeal)->getResponseData()->getResult()->getResultData()[0]; +// получили массив сделок +$deals = $dealsService->list([], [], [], 0)->getResponseData()->getResult()->getResultData(); +``` + +- отсутствие релевантной вызываемому методу типизации возвращаемого результата. + +Ожидание: + +``` + add(array $newDeal):int // идентификатор новой сделки + list(array $order, array $filter, array $select, int $start):array //массив сделок + постраничка + get(int $dealId):array // конкретная сделка +``` + +Текущая реализация — возвращается унифицированный результат: + +``` +add(array $newDeal):Core\Response +list(array $order, array $filter, array $select, int $start):Core\Response +``` + +#### Core – вызов произвольных API-методов + +Зона ответственности: + +- вызов **произвольных** API-методов +- обработка ошибок уровня API +- запрос нового токена и повторение запроса, если получили ошибку `expired_token` + +Входящие данные: + +- `string $apiMethod` – название api-метода +- `array $parameters = []` – аргументы метода + +Возвращаемый результат: `Core\Response` – **унифицированный** объект-обёртка, содержит: + +- `Symfony\Contracts\HttpClient\ResponseInterface` — объект ответа от сервера, может быть асинхронным +- `Core\Commands\Command` — информация о команде\аргументах которая была исполнена, используется при разборе пакетных запросов. + +Для получения результата запроса к API используется метод `Response::getResponseData`, который декодирует тело ответа вызвав +метод `Symfony\Contracts\HttpClient::toArray` +Возвращается стандартизированный DTO `ResponseData` от API-сервера с полями: + +- `Result` - DTO c результатом исполнения запроса; +- `Time` — DTO c таймингом прохождения запроса через сервера Битрикс24; +- `Pagination` — DTO постраничной навигации с полями `next` и `total`; В случае обнаружения ошибок уровня домена будет выброшено + соответствующее типизированное исключение. + +Объект `Result` содержит один метод `getResultData`, который возвращает массив с результатом исполнения API-запроса. В зависимости от +вызванного метода там может быть: + +- результат выполнения операции типа bool +- идентификатор созданной сущности типа int +- сущность + пользовательские поля с префиксами UF_ типа array +- массив сущностей типа array +- пустой массив как результат пустого фильтра. + +#### ApiClient — работа с сетью и эндпоинтами API-серверов + +Зона ответственности: + +- передача данных по сети +- соблюдение контракта на эндпоинты с которыми идёт работы +- «подпись» запросов токенами \ передача их в нужные входящие адреса если используется авторизация по вебхукам + +Используется: +Symfony HttpClient + +Входящие данные: + +- тип http-запроса +- массив с параметрами + +Возвращаемые результат: +— `Symfony\Contracts\HttpClient\ResponseInterface` + +#### Формат передачи данных по сети + +JSON по HTTP/2 или HTTP/1.1 \ No newline at end of file diff --git a/src/Services/CRM/Products/Service/Products.php b/src/Services/CRM/Products/Service/Products.php index 1cd00c99..9db66b13 100644 --- a/src/Services/CRM/Products/Service/Products.php +++ b/src/Services/CRM/Products/Service/Products.php @@ -72,12 +72,13 @@ public function delete(int $productId): Response * @param array $order * @param array $filter * @param array $select + * @param int $startItem * * @return Response * @throws BaseException * @throws TransportException */ - public function list(array $order, array $filter, array $select): Response + public function list(array $order, array $filter, array $select, int $startItem = 0): Response { $this->log->debug( 'list.start', @@ -85,6 +86,7 @@ public function list(array $order, array $filter, array $select): Response 'order' => $order, 'filter' => $filter, 'select' => $select, + 'start' => $startItem, ] ); @@ -94,6 +96,7 @@ public function list(array $order, array $filter, array $select): Response 'order' => $order, 'filter' => $filter, 'select' => $select, + 'start' => $startItem, ] ); From e5c914685aabf92dfcdd3ca66bae3631452ddd22 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 19 Dec 2020 19:25:36 +0300 Subject: [PATCH 186/647] fix sdk description in russian --- README.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 4f3fd787..9afa37c4 100644 --- a/README.md +++ b/README.md @@ -163,7 +163,7 @@ email: - длинные цепочки в клиентском коде для получения возвращаемого результата -``` +```php // добавили сделку в Б24 $dealId = $dealsService->add($newDeal)->getResponseData()->getResult()->getResultData()[0]; // получили массив сделок @@ -174,7 +174,7 @@ $deals = $dealsService->list([], [], [], 0)->getResponseData()->getResult()->get Ожидание: -``` +```php add(array $newDeal):int // идентификатор новой сделки list(array $order, array $filter, array $select, int $start):array //массив сделок + постраничка get(int $dealId):array // конкретная сделка @@ -182,7 +182,7 @@ $deals = $dealsService->list([], [], [], 0)->getResponseData()->getResult()->get Текущая реализация — возвращается унифицированный результат: -``` +```php add(array $newDeal):Core\Response list(array $order, array $filter, array $select, int $start):Core\Response ``` @@ -211,10 +211,11 @@ list(array $order, array $filter, array $select, int $start):Core\Response - `Result` - DTO c результатом исполнения запроса; - `Time` — DTO c таймингом прохождения запроса через сервера Битрикс24; -- `Pagination` — DTO постраничной навигации с полями `next` и `total`; В случае обнаружения ошибок уровня домена будет выброшено - соответствующее типизированное исключение. +- `Pagination` — DTO постраничной навигации с полями `next` и `total`; + +В случае обнаружения ошибок уровня домена будет выброшено соответствующее типизированное исключение. -Объект `Result` содержит один метод `getResultData`, который возвращает массив с результатом исполнения API-запроса. В зависимости от +Объект `Result` содержит метод `getResultData`, который возвращает массив с результатом исполнения API-запроса. В зависимости от вызванного метода там может быть: - результат выполнения операции типа bool @@ -239,7 +240,7 @@ Symfony HttpClient - тип http-запроса - массив с параметрами -Возвращаемые результат: +Возвращаемые результаты: — `Symfony\Contracts\HttpClient\ResponseInterface` #### Формат передачи данных по сети From 9d6570aa0bb282166f5fe878450a7a0a0d3a3270 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 19 Dec 2020 19:37:00 +0300 Subject: [PATCH 187/647] fix sdk description in russian --- README.md | 55 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 9afa37c4..446a3edf 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,7 @@ A powerful PHP library for the Bitrix24 REST API [Bitrix24 API documentation - English](https://training.bitrix24.com/rest_help/)
[Register new Bitrix24 account](https://www.bitrix24.ru/create.php?p=255670)
- -## SDK 2.0 core features +### SDK 2.0 core features Bitrix24 auth features @@ -43,12 +42,12 @@ Core DTO - ~~ApplicationProfile~~ - ~~Pagination~~ -## SDK Documentation +### SDK Documentation - [Russian](/docs/RU/documentation.md) - [English](/docs/EN/documentation.md) -## Architecture +### Architecture ### Abstraction layers @@ -82,56 +81,66 @@ Core DTO Main.php - default bitrix24 rest api service provide basic funcions, work with data transfer objects ``` -## Requirements +### Requirements - php: >=7.4 - ext-json: * - ext-curl: * -## Example ## +### Example -## Installation ## +### Installation Add `"mesilov/bitrix24-php-sdk": "2.x"` to `composer.json` of your application. Or clone repo to your project. -## Tests ## +### Tests SDK test locate in folder `tests` and we have two test types - Unit: **fast**, in-memory tests without a network I\O - Integration: **slow** tests with full lifecycle with test Bitrix24 portal via webhook -## Submitting bugs and feature requests +### Submitting bugs and feature requests Bugs and feature request are tracked on [GitHub](https://github.com/mesilov/bitrix24-php-sdk/issues) -## License +### License bitrix24-php-sdk is licensed under the MIT License - see the `MIT-LICENSE.txt` file for details -## Author +### Author Maxim Mesilov - -
See also the list of [contributors](https://github.com/mesilov/bitrix24-php-sdk/graphs/contributors) which participated in this project. -## Need custom Bitrix24 application? ## +### Need custom Bitrix24 application? ## email: +### Sponsors + + ## Русский + ### Принципы по которым ведётся разработка + - хороший DX (Developer Experience) + - автодополнение методов на уровне IDE + - типизированные сигнатуры вызова методов + - типизированные результаты вызова методов: используются нативные типы: int, array, bool, string - хорошая документация + - документация по работе конкретного метода содержащая ссылку на офф документацию + - документация по работе с SDK - производительность: - - SDK должно оказывать минимальное влияние на клиентский код - - должна быть возможность работать с большими объёмами данных с константным потреблением памяти - - SDK должно обеспечивать эффективную работу c API: поддержка батч-запросов + - минимальное влияние на клиентский код + - возможность работать с большими объёмами данных с константным потреблением памяти + - эффективна работа c API с использованием батч-запросов - работать на современном стеке технологий: - - использовать современные библиотеки для работы с сетью - - использовать фичи новых версий PHP + - современные библиотеки для работы с сетью и возможностью асинхронной работы + - фичи новых версий PHP - надёжной: - - SDK покрыта тестами: unit, интеграционные, контрактные - - SDK имеет типовые примеры характерные для разных режимов работы и они оптимизированы по памяти \ быстродействию + - покрытие тестами: unit, интеграционные, контрактные + - есть типовые примеры характерные для разных режимов работы и они оптимизированы по памяти \ быстродействию ### Ключевые особенности @@ -215,8 +224,8 @@ list(array $order, array $filter, array $select, int $start):Core\Response В случае обнаружения ошибок уровня домена будет выброшено соответствующее типизированное исключение. -Объект `Result` содержит метод `getResultData`, который возвращает массив с результатом исполнения API-запроса. В зависимости от -вызванного метода там может быть: +Объект `Result` содержит метод `getResultData`, который возвращает массив с результатом исполнения API-запроса. В зависимости от вызванного +метода там может быть: - результат выполнения операции типа bool - идентификатор созданной сущности типа int @@ -245,4 +254,6 @@ Symfony HttpClient #### Формат передачи данных по сети -JSON по HTTP/2 или HTTP/1.1 \ No newline at end of file +JSON по HTTP/2 или HTTP/1.1 + +## Спонсоры \ No newline at end of file From c2a3d46d148ec67589c7ad199c8da1969d29ebca Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 19 Dec 2020 19:39:09 +0300 Subject: [PATCH 188/647] fix sdk description in russian --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 446a3edf..e82d3362 100644 --- a/README.md +++ b/README.md @@ -127,16 +127,16 @@ email: - хороший DX (Developer Experience) - автодополнение методов на уровне IDE - типизированные сигнатуры вызова методов - - типизированные результаты вызова методов: используются нативные типы: int, array, bool, string + - типизированные результаты вызова методов - используются нативные типы: int, array, bool, string - хорошая документация - документация по работе конкретного метода содержащая ссылку на офф документацию - документация по работе с SDK - производительность: - минимальное влияние на клиентский код - возможность работать с большими объёмами данных с константным потреблением памяти - - эффективна работа c API с использованием батч-запросов -- работать на современном стеке технологий: - - современные библиотеки для работы с сетью и возможностью асинхронной работы + - эффективная работа c API с использованием батч-запросов +- современный стек технологий: + - библиотеки для работы с сетью и возможностью асинхронной работы - фичи новых версий PHP - надёжной: - покрытие тестами: unit, интеграционные, контрактные From c9b372d2dc6183cd36c134b1bab6ec3e03aecf54 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 10 Jan 2021 20:15:22 +0300 Subject: [PATCH 189/647] add result description --- docs/RU/Core/Result/result.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 docs/RU/Core/Result/result.md diff --git a/docs/RU/Core/Result/result.md b/docs/RU/Core/Result/result.md new file mode 100644 index 00000000..f1b79411 --- /dev/null +++ b/docs/RU/Core/Result/result.md @@ -0,0 +1,29 @@ +# Типизированные результаты вызова API-методов + +Результатом работы API-методов является унифицированный объект `SDK\Core\Response\Response`, но с ним неудобно работать, т.к. он +предоставляет только «общие» методы. В зависимости от типа API-метода сервисы SDK возвращают типизированные результаты. + +## Общие принципы + +1. Сервисы возвращают типизированные результаты +2. Результаты работы сервиса находятся в одноимённом пространстве имён `Result` который принадлежит сервису сущности. +3. Часть унифицированных результатов вынесена в пространство имён `Core\Result` и используется всеми сервисами, унифицированные результаты + перечислены ниже: + +## Результат добавления сущности — AddItemResult + +Является результатом добавления сущности при вызове метода *.add + +Содержит метод `getId():int` который позволяет получить идентификатор добавленной сущности. + +## Результат удаления сущности — DeleteItemResult + +Является результатом удаления сущности при вызове метода *.delete + +Содержит метод `isSuccess(): bool` который позволяет понять, была ли успешна операция удаления сущности. + +## Результат получения описания списка полей — FieldsResult + +Является результатом вызова метода с описанием метаданных полей *.fields + +Содержит метод `getFieldsDescription(): array` который позволяет получить описание полей для конкретной сущности \ No newline at end of file From 74abb7c805b31f0b8ab7e739185e6292d4fd824a Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 10 Jan 2021 20:18:08 +0300 Subject: [PATCH 190/647] add result description documentation.md --- docs/RU/documentation.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/RU/documentation.md b/docs/RU/documentation.md index e7d9b782..1b40befb 100644 --- a/docs/RU/documentation.md +++ b/docs/RU/documentation.md @@ -10,6 +10,10 @@ - унифицированный объект [Response](Core/Response/response.md) +## Возвращаемые результаты сервисов + +- унифицированные объекты [Result](Core/Result/result.md) + ## Обработка событий При работе с SDK могут возникать события, которые требуется обработать в клиентском коде. Библиотека позволяет подписаться на эти события с From e61298cfd0c856ee407ad329a5606b34b58c277a Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 10 Jan 2021 21:09:50 +0300 Subject: [PATCH 191/647] add base results and tests --- docs/RU/Core/Result/result.md | 59 +++++++++++++- .../ImmutableResultViolationException.php | 14 ++++ src/Core/Result/AbstractItem.php | 78 +++++++++++++++++++ src/Core/Result/AbstractResult.php | 35 +++++++++ src/Core/Result/AddItemResult.php | 24 ++++++ src/Core/Result/DeleteItemResult.php | 24 ++++++ src/Core/Result/FieldsResult.php | 24 ++++++ tests/Unit/Core/Result/AbstractItemTest.php | 38 +++++++++ 8 files changed, 295 insertions(+), 1 deletion(-) create mode 100644 src/Core/Exceptions/ImmutableResultViolationException.php create mode 100644 src/Core/Result/AbstractItem.php create mode 100644 src/Core/Result/AbstractResult.php create mode 100644 src/Core/Result/AddItemResult.php create mode 100644 src/Core/Result/DeleteItemResult.php create mode 100644 src/Core/Result/FieldsResult.php create mode 100644 tests/Unit/Core/Result/AbstractItemTest.php diff --git a/docs/RU/Core/Result/result.md b/docs/RU/Core/Result/result.md index f1b79411..41dd354c 100644 --- a/docs/RU/Core/Result/result.md +++ b/docs/RU/Core/Result/result.md @@ -26,4 +26,61 @@ Является результатом вызова метода с описанием метаданных полей *.fields -Содержит метод `getFieldsDescription(): array` который позволяет получить описание полей для конкретной сущности \ No newline at end of file +Содержит метод `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/src/Core/Exceptions/ImmutableResultViolationException.php b/src/Core/Exceptions/ImmutableResultViolationException.php new file mode 100644 index 00000000..1765180c --- /dev/null +++ b/src/Core/Exceptions/ImmutableResultViolationException.php @@ -0,0 +1,14 @@ +data = $data; + } + + /** + * @param int|string $offset + * + * @return bool + */ + public function __isset($offset): bool + { + return isset($this->data[$offset]); + } + + /** + * @param int|string $offset + * + * @return mixed + */ + public function __get($offset) + { + return $this->data[$offset] ?? null; + } + + /** + * @param int|string $offset + * @param mixed $value + * + * @return void + * @throws ImmutableResultViolationException + * + */ + public function __set($offset, $value) + { + throw new ImmutableResultViolationException(sprintf('Result is immutable, violation at offset %s', $offset)); + } + + /** + * @param int|string $offset + * + * @throws ImmutableResultViolationException + */ + public function __unset($offset) + { + throw new ImmutableResultViolationException(sprintf('Result is immutable, violation at offset %s', $offset)); + } + + /** + * {@inheritdoc} + */ + public function getIterator() + { + return new \ArrayIterator($this->data); + } +} \ No newline at end of file diff --git a/src/Core/Result/AbstractResult.php b/src/Core/Result/AbstractResult.php new file mode 100644 index 00000000..1eac6f05 --- /dev/null +++ b/src/Core/Result/AbstractResult.php @@ -0,0 +1,35 @@ +coreResponse = $coreResponse; + } + + /** + * @return Response + */ + public function getCoreResponse(): Response + { + return $this->coreResponse; + } +} \ No newline at end of file diff --git a/src/Core/Result/AddItemResult.php b/src/Core/Result/AddItemResult.php new file mode 100644 index 00000000..3a721da9 --- /dev/null +++ b/src/Core/Result/AddItemResult.php @@ -0,0 +1,24 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + } +} \ No newline at end of file diff --git a/src/Core/Result/DeleteItemResult.php b/src/Core/Result/DeleteItemResult.php new file mode 100644 index 00000000..bc624a58 --- /dev/null +++ b/src/Core/Result/DeleteItemResult.php @@ -0,0 +1,24 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + } +} \ No newline at end of file diff --git a/src/Core/Result/FieldsResult.php b/src/Core/Result/FieldsResult.php new file mode 100644 index 00000000..e997af4f --- /dev/null +++ b/src/Core/Result/FieldsResult.php @@ -0,0 +1,24 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData(); + } +} \ No newline at end of file diff --git a/tests/Unit/Core/Result/AbstractItemTest.php b/tests/Unit/Core/Result/AbstractItemTest.php new file mode 100644 index 00000000..add2fef0 --- /dev/null +++ b/tests/Unit/Core/Result/AbstractItemTest.php @@ -0,0 +1,38 @@ +expectException(ImmutableResultViolationException::class); + $testItem = new class (['ID' => 1]) extends AbstractItem { + }; + $testItem->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); + } +} \ No newline at end of file From a6312d39439c05ecd74fe08422a43dd2b0c62fcb Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 10 Jan 2021 22:11:14 +0300 Subject: [PATCH 192/647] fix errors --- src/Core/Response/Response.php | 51 +++++++++++++++++----------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/src/Core/Response/Response.php b/src/Core/Response/Response.php index 8b98211f..92ce2d47 100644 --- a/src/Core/Response/Response.php +++ b/src/Core/Response/Response.php @@ -18,22 +18,10 @@ */ class Response { - /** - * @var ResponseInterface - */ - protected $httpResponse; - /** - * @var LoggerInterface - */ - protected $logger; - /** - * @var DTO\ResponseData - */ - protected $responseData; - /** - * @var Command - */ - protected $apiCommand; + protected ResponseInterface $httpResponse; + protected LoggerInterface $logger; + protected ?DTO\ResponseData $responseData; + protected Command $apiCommand; /** * Response constructor. @@ -47,6 +35,7 @@ public function __construct(ResponseInterface $httpResponse, Command $apiCommand $this->httpResponse = $httpResponse; $this->apiCommand = $apiCommand; $this->logger = $logger; + $this->responseData = null; } /** @@ -68,10 +57,6 @@ public function getApiCommand(): Command /** * @return DTO\ResponseData * @throws BaseException - * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface - * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface - * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface - * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface */ public function getResponseData(): DTO\ResponseData { @@ -80,6 +65,7 @@ public function getResponseData(): DTO\ResponseData if ($this->responseData === null) { try { $responseResult = $this->httpResponse->toArray(true); + // try to handle api-level errors $this->handleApiLevelErrors($responseResult); if (!is_array($responseResult['result'])) { @@ -100,14 +86,14 @@ public function getResponseData(): DTO\ResponseData DTO\Time::initFromResponse($responseResult['time']), new DTO\Pagination($nextItem, $total) ); - } catch (Throwable $e) { + } catch (Throwable $exception) { $this->logger->error( - $e->getMessage(), + $exception->getMessage(), [ - 'response' => $this->httpResponse->getContent(false), + 'response' => $this->getHttpResponseContent(), ] ); - throw new BaseException(sprintf('api request error: %s', $e->getMessage()), $e->getCode(), $e); + throw new BaseException(sprintf('api request error: %s', $exception->getMessage()), $exception->getCode(), $exception); } } $this->logger->debug('getResponseData.finish'); @@ -115,6 +101,20 @@ public function getResponseData(): DTO\ResponseData 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()); + } + + return $content; + } /** * @param array $apiResponse @@ -129,7 +129,8 @@ private function handleApiLevelErrors(array $apiResponse): void $apiResponse['error'], (array_key_exists('error_description', $apiResponse) ? $apiResponse['error_description'] : ''), ); - +// todo check api-level error codes +// // switch (strtoupper(trim($apiResponse['error']))) { // case 'EXPIRED_TOKEN': // throw new Bitrix24TokenIsExpiredException($errorMsg); From ed4974730cec237a0be468bec9a0b5672b3fca9a Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 16 Jan 2021 00:00:52 +0300 Subject: [PATCH 193/647] add show fields description command --- tools/ShowFieldsDescriptionCommand.php | 201 +++++++++++++++++++++++++ tools/bin/console | 2 + 2 files changed, 203 insertions(+) create mode 100644 tools/ShowFieldsDescriptionCommand.php diff --git a/tools/ShowFieldsDescriptionCommand.php b/tools/ShowFieldsDescriptionCommand.php new file mode 100644 index 00000000..a16210ce --- /dev/null +++ b/tools/ShowFieldsDescriptionCommand.php @@ -0,0 +1,201 @@ +logger = $logger; + parent::__construct(); + } + + /** + * настройки + */ + protected function configure(): void + { + $this + ->setDescription('show entity fields description with table or phpDoc output format') + ->setHelp('get list of *.fields methods and show fields description for selected entity') + ->addOption( + self::WEBHOOK_URL, + null, + InputOption::VALUE_REQUIRED, + 'bitrix24 incoming webhook', + '' + ) + ->addOption( + self::IS_SHOW_TABLE, + null, + InputOption::VALUE_OPTIONAL, + 'show fields as table', + true + ); + } + + /** + * @param InputInterface $input + * @param OutputInterface $output + * + * @return int + */ + protected function execute(InputInterface $input, OutputInterface $output): int + { + $b24Webhook = (string)$input->getOption(self::WEBHOOK_URL); + $isShowTable = $input->getOption(self::IS_SHOW_TABLE) === 'true'; + + $io = new SymfonyStyle($input, $output); + try { + $this->core = (new \Bitrix24\SDK\Core\CoreBuilder()) + ->withLogger($this->logger) + ->withWebhookUrl($b24Webhook) + ->build(); + + $methods = $this->core->call('methods', ['full' => true])->getResponseData()->getResult()->getResultData(); + $fieldsMethods = []; + foreach ($methods as $method) { + if (strpos($method, 'fields') !== false) { + $fieldsMethods[] = $method; + } + } + + $helper = $this->getHelper('question'); + $question = new ChoiceQuestion( + 'Please select item number to see fields', + $fieldsMethods, + null + ); + $question->setErrorMessage('Item number %s is invalid.'); + $selectedEntity = $helper->ask($input, $output, $question); + $output->writeln('You have just selected: ' . $selectedEntity); + + $fields = $this->core->call($selectedEntity); + + if ($isShowTable) { + var_dump($fields->getResponseData()->getResult()->getResultData()); + + $this->showFieldsAsTable($output, $fields); + } else { + $this->showFieldsAsPhpDocHeader($output, $fields); + } + } catch (BaseException $exception) { + $io->caution('Bitrix24 error'); + $io->text( + [ + sprintf('%s', $exception->getMessage()), + ] + ); + } catch (\Throwable $exception) { + $io->caution('fatal error'); + $io->text( + [ + $exception->getMessage(), + $exception->getTraceAsString(), + ] + ); + } + $this->logger->debug('ListCommand.start.finish'); + + return self::SUCCESS; + } + + /** + * @param OutputInterface $output + * @param Response $fields + * + * @throws BaseException + */ + private function showFieldsAsPhpDocHeader(OutputInterface $output, Response $fields): void + { + $fieldsList = ['/**', '*']; + foreach ($fields->getResponseData()->getResult()->getResultData() as $fieldCode => $fieldDescription) { + switch (strtolower($fieldDescription['type'])) { + case 'integer': + $phpDocType = 'int'; + break; + case 'datetime': + $phpDocType = 'string'; + break; + default: + $phpDocType = 'string'; + } + $fieldsList[] = sprintf('* @property-read %s $%s', $phpDocType, $fieldCode); + } + $fieldsList[] = '*/'; + $output->writeln($fieldsList); + } + + /** + * @param OutputInterface $output + * @param Response $fields + * + * @throws BaseException + */ + private function showFieldsAsTable(OutputInterface $output, Response $fields): void + { + $fieldsTable = []; + // some methods return description in upper case + $fields = array_change_key_case($fields->getResponseData()->getResult()->getResultData(), CASE_LOWER); + + foreach ($fields as $fieldCode => $fieldDescription) { + $fieldDescription = array_change_key_case($fieldDescription, CASE_LOWER); + if (!array_key_exists('title', $fieldDescription)) { + $fieldDescription['title'] = $fieldCode; + } + + $fieldsTable[] = [ + $fieldCode, + $fieldDescription['title'], + $fieldDescription['type'], + $fieldDescription['isrequired'] ? 'Y' : '', + $fieldDescription['isreadonly'] ? 'Y' : '', + $fieldDescription['isimmutable'] ? 'Y' : '', + $fieldDescription['ismultiple'] ? 'Y' : '', + $fieldDescription['isdynamic'] ? 'Y' : '', + ]; + } + + $table = new Table($output); + $table + ->setHeaders(['Code', 'Title', 'Type', 'isRequired', 'isReadOnly', 'isImmutable', 'isMultiple', 'isDynamic']) + ->setRows($fieldsTable); + $table->render(); + } +} \ No newline at end of file diff --git a/tools/bin/console b/tools/bin/console index df7d24ce..c0c6a43f 100644 --- a/tools/bin/console +++ b/tools/bin/console @@ -3,6 +3,7 @@ use Bitrix24\SDK\Tools\DemoDataGenerators\CRM\Contacts\GenerateContactsCommand; use Bitrix24\SDK\Tools\PerformanceBenchmarks\ListCommand; +use Bitrix24\SDK\Tools\ShowFieldsDescriptionCommand; use Monolog\Handler\StreamHandler; use Monolog\Logger; use Symfony\Component\Console\Application; @@ -50,4 +51,5 @@ $log->pushProcessor(new \Monolog\Processor\MemoryUsageProcessor(true, true)); $application = new Application(); $application->add(new GenerateContactsCommand($log)); $application->add(new ListCommand($log)); +$application->add(new ShowFieldsDescriptionCommand($log)); $application->run($input); \ No newline at end of file From 119c01ae0032d2ea61a8301d7e8dab70f8fc6b52 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 16 Jan 2021 00:01:32 +0300 Subject: [PATCH 194/647] update documentation --- docs/RU/Core/Result/result.md | 8 +++++++- docs/RU/documentation.md | 23 ++++++++++++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/docs/RU/Core/Result/result.md b/docs/RU/Core/Result/result.md index 41dd354c..129ff907 100644 --- a/docs/RU/Core/Result/result.md +++ b/docs/RU/Core/Result/result.md @@ -16,12 +16,18 @@ Содержит метод `getId():int` который позволяет получить идентификатор добавленной сущности. -## Результат удаления сущности — DeleteItemResult +## Результат удаления сущности — DeletedItemResult Является результатом удаления сущности при вызове метода *.delete Содержит метод `isSuccess(): bool` который позволяет понять, была ли успешна операция удаления сущности. +## Результат изменения сущности — UpdatedItemResult + +Является результатом изменения сущности при вызове метода *.update + +Содержит метод `isSuccess(): bool` который позволяет понять, была ли успешна операция изменения сущности. + ## Результат получения описания списка полей — FieldsResult Является результатом вызова метода с описанием метаданных полей *.fields diff --git a/docs/RU/documentation.md b/docs/RU/documentation.md index 1b40befb..31b70eaa 100644 --- a/docs/RU/documentation.md +++ b/docs/RU/documentation.md @@ -79,4 +79,25 @@ SDK разбита на сервисы которые соответствуют отвечающих за работу с CRM. Сервисы предоставляют CRUD+ API по работе с конкретной сущностью, сервис именуется так же как сущность. Сервис по работе со сделками будет -доступен при вызове `CRM\Deals\Service\Deals` \ No newline at end of file +доступен при вызове `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 From 5ecdf3b835e58bf3228b0ac6ec0f0e370a5602b8 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 16 Jan 2021 09:59:43 +0300 Subject: [PATCH 195/647] add property fields description generator --- tools/ShowFieldsDescriptionCommand.php | 61 +++++++++++++++++++------- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/tools/ShowFieldsDescriptionCommand.php b/tools/ShowFieldsDescriptionCommand.php index a16210ce..168ac21b 100644 --- a/tools/ShowFieldsDescriptionCommand.php +++ b/tools/ShowFieldsDescriptionCommand.php @@ -30,7 +30,7 @@ class ShowFieldsDescriptionCommand extends Command */ protected static $defaultName = 'util:show-fields-description'; protected const WEBHOOK_URL = 'webhook'; - protected const IS_SHOW_TABLE = 'is-show-table'; + protected const OUTPUT_FORMAT = 'output-format'; /** * ListCommand constructor. @@ -46,9 +46,6 @@ public function __construct(LoggerInterface $logger) parent::__construct(); } - /** - * настройки - */ protected function configure(): void { $this @@ -62,11 +59,11 @@ protected function configure(): void '' ) ->addOption( - self::IS_SHOW_TABLE, + self::OUTPUT_FORMAT, null, InputOption::VALUE_OPTIONAL, - 'show fields as table', - true + 'show fields as «table» or «class» header or function «property» enum', + 'table' ); } @@ -79,7 +76,7 @@ protected function configure(): void protected function execute(InputInterface $input, OutputInterface $output): int { $b24Webhook = (string)$input->getOption(self::WEBHOOK_URL); - $isShowTable = $input->getOption(self::IS_SHOW_TABLE) === 'true'; + $outputFormat = strtolower($input->getOption(self::OUTPUT_FORMAT)); $io = new SymfonyStyle($input, $output); try { @@ -107,13 +104,18 @@ protected function execute(InputInterface $input, OutputInterface $output): int $output->writeln('You have just selected: ' . $selectedEntity); $fields = $this->core->call($selectedEntity); - - if ($isShowTable) { - var_dump($fields->getResponseData()->getResult()->getResultData()); - - $this->showFieldsAsTable($output, $fields); - } else { - $this->showFieldsAsPhpDocHeader($output, $fields); + switch ($outputFormat) { + case 'table': + $this->showFieldsAsTable($output, $fields); + break; + case 'class': + $this->showFieldsAsPhpDocClassHeader($output, $fields); + break; + case 'property': + $this->showFieldsAsPhpDocFunctionProperty($output, $fields); + break; + default: + throw new \InvalidArgumentException(sprintf('unknown output format %s', $outputFormat)); } } catch (BaseException $exception) { $io->caution('Bitrix24 error'); @@ -142,7 +144,34 @@ protected function execute(InputInterface $input, OutputInterface $output): int * * @throws BaseException */ - private function showFieldsAsPhpDocHeader(OutputInterface $output, Response $fields): void + private function showFieldsAsPhpDocFunctionProperty(OutputInterface $output, Response $fields): void + { + $fieldsList = ['*', '* @param array{']; + foreach ($fields->getResponseData()->getResult()->getResultData() as $fieldCode => $fieldDescription) { + switch (strtolower($fieldDescription['type'])) { + case 'integer': + $phpDocType = 'int'; + break; + case 'datetime': + $phpDocType = 'string'; + break; + default: + $phpDocType = 'string'; + } + $fieldsList[] = sprintf('* %s?: %s,', $fieldCode, $phpDocType); + } + $fieldsList[] = '* } $fields'; + $fieldsList[] = '*'; + $output->writeln($fieldsList); + } + + /** + * @param OutputInterface $output + * @param Response $fields + * + * @throws BaseException + */ + private function showFieldsAsPhpDocClassHeader(OutputInterface $output, Response $fields): void { $fieldsList = ['/**', '*']; foreach ($fields->getResponseData()->getResult()->getResultData() as $fieldCode => $fieldDescription) { From 4a98c9578928f1598a4bab20082228da78d8c82b Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 16 Jan 2021 15:46:52 +0300 Subject: [PATCH 196/647] add property enum fields description --- tools/ShowFieldsDescriptionCommand.php | 44 ++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/tools/ShowFieldsDescriptionCommand.php b/tools/ShowFieldsDescriptionCommand.php index 168ac21b..fd23ea2e 100644 --- a/tools/ShowFieldsDescriptionCommand.php +++ b/tools/ShowFieldsDescriptionCommand.php @@ -62,7 +62,7 @@ protected function configure(): void self::OUTPUT_FORMAT, null, InputOption::VALUE_OPTIONAL, - 'show fields as «table» or «class» header or function «property» enum', + 'show fields as «table» or «class» header or function «property» enum or «select» property', 'table' ); } @@ -94,26 +94,43 @@ protected function execute(InputInterface $input, OutputInterface $output): int } $helper = $this->getHelper('question'); - $question = new ChoiceQuestion( + $itemQuestion = new ChoiceQuestion( 'Please select item number to see fields', $fieldsMethods, null ); - $question->setErrorMessage('Item number %s is invalid.'); - $selectedEntity = $helper->ask($input, $output, $question); + $itemQuestion->setErrorMessage('Item number %s is invalid.'); + $selectedEntity = $helper->ask($input, $output, $itemQuestion); $output->writeln('You have just selected: ' . $selectedEntity); + $outputQuestion = new ChoiceQuestion( + 'Please select item number to see fields', + [ + 'class properties header', + 'hashmap for function argument', + 'enum for function argument', + 'table', + ], + 'table' + ); + $outputQuestion->setErrorMessage('Item number %s is invalid.'); + $outputFormat = $helper->ask($input, $output, $outputQuestion); + $output->writeln('You have just selected: ' . $outputFormat); + $fields = $this->core->call($selectedEntity); switch ($outputFormat) { case 'table': $this->showFieldsAsTable($output, $fields); break; - case 'class': + case 'class properties header': $this->showFieldsAsPhpDocClassHeader($output, $fields); break; - case 'property': + case 'hashmap for function argument': $this->showFieldsAsPhpDocFunctionProperty($output, $fields); break; + case 'enum for function argument': + $this->showFieldsAsPhpDocFunctionSelectSuggest($output, $fields); + break; default: throw new \InvalidArgumentException(sprintf('unknown output format %s', $outputFormat)); } @@ -138,6 +155,21 @@ protected function execute(InputInterface $input, OutputInterface $output): int return self::SUCCESS; } + /** + * @param OutputInterface $output + * @param Response $fields + * + * @throws BaseException + */ + private function showFieldsAsPhpDocFunctionSelectSuggest(OutputInterface $output, Response $fields): void + { + $fieldsList = []; + foreach ($fields->getResponseData()->getResult()->getResultData() as $fieldCode => $fieldDescription) { + $fieldsList[] = sprintf("'%s'", $fieldCode); + } + $output->writeln(' * @param array $select = [' . implode(',', $fieldsList) . ']'); + } + /** * @param OutputInterface $output * @param Response $fields From 7e6958d7b242c9b1fa5ec262b9498c07ab56a53a Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 16 Jan 2021 16:07:44 +0300 Subject: [PATCH 197/647] add contact entity --- ...{AddItemResult.php => AddedItemResult.php} | 4 +- ...teItemResult.php => DeletedItemResult.php} | 4 +- src/Core/Result/UpdatedItemResult.php | 24 ++ src/Services/AbstractService.php | 5 +- src/Services/CRM/CRMServiceBuilder.php | 79 ++-- .../CRM/Contact/Result/ContactItemResult.php | 62 +++ .../CRM/Contact/Result/ContactResult.php | 21 + src/Services/CRM/Contact/Service/Batch.php | 59 +++ src/Services/CRM/Contact/Service/Contact.php | 376 ++++++++++++++++++ .../CRM/Contacts/Service/Contacts.php | 206 ---------- .../CRM/Contact/Service/ContactTest.php | 94 +++++ 11 files changed, 696 insertions(+), 238 deletions(-) rename src/Core/Result/{AddItemResult.php => AddedItemResult.php} (84%) rename src/Core/Result/{DeleteItemResult.php => DeletedItemResult.php} (83%) create mode 100644 src/Core/Result/UpdatedItemResult.php create mode 100644 src/Services/CRM/Contact/Result/ContactItemResult.php create mode 100644 src/Services/CRM/Contact/Result/ContactResult.php create mode 100644 src/Services/CRM/Contact/Service/Batch.php create mode 100644 src/Services/CRM/Contact/Service/Contact.php delete mode 100644 src/Services/CRM/Contacts/Service/Contacts.php create mode 100644 tests/Integration/Services/CRM/Contact/Service/ContactTest.php diff --git a/src/Core/Result/AddItemResult.php b/src/Core/Result/AddedItemResult.php similarity index 84% rename from src/Core/Result/AddItemResult.php rename to src/Core/Result/AddedItemResult.php index 3a721da9..5385fe1b 100644 --- a/src/Core/Result/AddItemResult.php +++ b/src/Core/Result/AddedItemResult.php @@ -7,11 +7,11 @@ use Bitrix24\SDK\Core\Exceptions\BaseException; /** - * Class AddItemResult + * Class AddedItemResult * * @package Bitrix24\SDK\Core\Result */ -class AddItemResult extends AbstractResult +class AddedItemResult extends AbstractResult { /** * @return int diff --git a/src/Core/Result/DeleteItemResult.php b/src/Core/Result/DeletedItemResult.php similarity index 83% rename from src/Core/Result/DeleteItemResult.php rename to src/Core/Result/DeletedItemResult.php index bc624a58..5ea0e838 100644 --- a/src/Core/Result/DeleteItemResult.php +++ b/src/Core/Result/DeletedItemResult.php @@ -7,11 +7,11 @@ use Bitrix24\SDK\Core\Exceptions\BaseException; /** - * Class DeleteItemResult + * Class DeletedItemResult * * @package Bitrix24\SDK\Core\Result */ -class DeleteItemResult extends AbstractResult +class DeletedItemResult extends AbstractResult { /** * @return bool diff --git a/src/Core/Result/UpdatedItemResult.php b/src/Core/Result/UpdatedItemResult.php new file mode 100644 index 00000000..7ee545e9 --- /dev/null +++ b/src/Core/Result/UpdatedItemResult.php @@ -0,0 +1,24 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + } +} \ No newline at end of file diff --git a/src/Services/AbstractService.php b/src/Services/AbstractService.php index 5a505d58..c4be48a3 100644 --- a/src/Services/AbstractService.php +++ b/src/Services/AbstractService.php @@ -15,7 +15,6 @@ */ abstract class AbstractService { - protected BatchInterface $batch; protected CoreInterface $core; protected LoggerInterface $log; @@ -23,13 +22,11 @@ abstract class AbstractService * AbstractService constructor. * * @param CoreInterface $core - * @param BatchInterface $batch * @param LoggerInterface $log */ - public function __construct(CoreInterface $core, BatchInterface $batch, LoggerInterface $log) + public function __construct(CoreInterface $core, LoggerInterface $log) { $this->core = $core; - $this->batch = $batch; $this->log = $log; } } \ No newline at end of file diff --git a/src/Services/CRM/CRMServiceBuilder.php b/src/Services/CRM/CRMServiceBuilder.php index 7127870d..36a13798 100644 --- a/src/Services/CRM/CRMServiceBuilder.php +++ b/src/Services/CRM/CRMServiceBuilder.php @@ -5,12 +5,11 @@ namespace Bitrix24\SDK\Services\CRM; use Bitrix24\SDK\Services\AbstractServiceBuilder; -use Bitrix24\SDK\Services\CRM\Contacts\Service\Contacts; -use Bitrix24\SDK\Services\CRM\Deals\Service\DealCategory; -use Bitrix24\SDK\Services\CRM\Deals\Service\DealCategoryStages; -use Bitrix24\SDK\Services\CRM\Deals\Service\DealProductRows; -use Bitrix24\SDK\Services\CRM\Deals\Service\Deals; -use Bitrix24\SDK\Services\CRM\Products\Service\Products; +use Bitrix24\SDK\Services\CRM\Contact; +use Bitrix24\SDK\Services\CRM\Deal; +use Bitrix24\SDK\Services\CRM\Products; +use Bitrix24\SDK\Services\CRM\Settings; + /** * Class CRMServiceBuilder @@ -20,72 +19,104 @@ class CRMServiceBuilder extends AbstractServiceBuilder { /** - * @return DealCategory + * @return Settings\Service\Settings + */ + public function settings(): Settings\Service\Settings + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Settings\Service\Settings($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + /** + * @return Deal\Service\DealContact + */ + public function dealContact(): Deal\Service\DealContact + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Deal\Service\DealContact($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + /** + * @return Deal\Service\DealCategory */ - public function dealCategory(): DealCategory + public function dealCategory(): Deal\Service\DealCategory { if (!isset($this->serviceCache[__METHOD__])) { - $this->serviceCache[__METHOD__] = new DealCategory($this->core, $this->batch, $this->log); + $this->serviceCache[__METHOD__] = new Deal\Service\DealCategory($this->core, $this->log); } return $this->serviceCache[__METHOD__]; } /** - * @return Deals + * @return Deal\Service\Deal */ - public function deals(): Deals + public function deal(): Deal\Service\Deal { if (!isset($this->serviceCache[__METHOD__])) { - $this->serviceCache[__METHOD__] = new Deals($this->core, $this->batch, $this->log); + $this->serviceCache[__METHOD__] = new Deal\Service\Deal( + new Deal\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); } return $this->serviceCache[__METHOD__]; } /** - * @return Products + * @return Deal\Service\Products */ - public function products(): Products + public function products(): Deal\Service\Products { if (!isset($this->serviceCache[__METHOD__])) { - $this->serviceCache[__METHOD__] = new Products($this->core, $this->batch, $this->log); + $this->serviceCache[__METHOD__] = new Deal\Service\Products($this->core, $this->log); } return $this->serviceCache[__METHOD__]; } /** - * @return Contacts + * @return Contact\Service\Contact */ - public function contacts(): Contacts + public function contact(): Contact\Service\Contact { if (!isset($this->serviceCache[__METHOD__])) { - $this->serviceCache[__METHOD__] = new Contacts($this->core, $this->batch, $this->log); + $this->serviceCache[__METHOD__] = new Contact\Service\Contact( + new Contact\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); } return $this->serviceCache[__METHOD__]; } /** - * @return DealProductRows + * @return Deal\Service\DealProductRows */ - public function dealProductRows(): DealProductRows + public function dealProductRows(): Deal\Service\DealProductRows { if (!isset($this->serviceCache[__METHOD__])) { - $this->serviceCache[__METHOD__] = new DealProductRows($this->core, $this->batch, $this->log); + $this->serviceCache[__METHOD__] = new Deal\Service\DealProductRows($this->core, $this->batch, $this->log); } return $this->serviceCache[__METHOD__]; } /** - * @return DealCategoryStages + * @return Deal\Service\DealCategoryStages */ - public function dealCategoryStages(): DealCategoryStages + public function dealCategoryStages(): Deal\Service\DealCategoryStages { if (!isset($this->serviceCache[__METHOD__])) { - $this->serviceCache[__METHOD__] = new DealCategoryStages($this->core, $this->batch, $this->log); + $this->serviceCache[__METHOD__] = new Deal\Service\DealCategoryStages($this->core, $this->batch, $this->log); } return $this->serviceCache[__METHOD__]; diff --git a/src/Services/CRM/Contact/Result/ContactItemResult.php b/src/Services/CRM/Contact/Result/ContactItemResult.php new file mode 100644 index 00000000..d2e50906 --- /dev/null +++ b/src/Services/CRM/Contact/Result/ContactItemResult.php @@ -0,0 +1,62 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData()); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Contact/Service/Batch.php b/src/Services/CRM/Contact/Service/Batch.php new file mode 100644 index 00000000..e39e7815 --- /dev/null +++ b/src/Services/CRM/Contact/Service/Batch.php @@ -0,0 +1,59 @@ +batch = $batch; + $this->log = $log; + } + + /** + * @param array $order + * @param array $filter + * @param array $select + * @param int|null $limit + * + * @return Generator + * @throws BaseException + */ + public function batchList(array $order, array $filter, array $select, ?int $limit = null): Generator + { + $this->log->debug( + 'batchList', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'limit' => $limit, + ] + ); + foreach ($this->batch->getTraversableList('crm.contact.list', $order, $filter, $select, $limit) as $key => $value) { + yield $key => new ContactItemResult($value); + } + } +} \ No newline at end of file diff --git a/src/Services/CRM/Contact/Service/Contact.php b/src/Services/CRM/Contact/Service/Contact.php new file mode 100644 index 00000000..d779bf31 --- /dev/null +++ b/src/Services/CRM/Contact/Service/Contact.php @@ -0,0 +1,376 @@ +batch = $batch; + } + + /** + * Creates and adds a new contact. + * + * @link https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_add.php + * + * @param array{ + * ID?: int, + * HONORIFIC?: string, + * NAME?: string, + * SECOND_NAME?: string, + * LAST_NAME?: string, + * PHOTO?: string, + * BIRTHDATE?: string, + * TYPE_ID?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: string, + * POST?: string, + * ADDRESS?: string, + * ADDRESS_2?: string, + * ADDRESS_CITY?: string, + * ADDRESS_POSTAL_CODE?: string, + * ADDRESS_REGION?: string, + * ADDRESS_PROVINCE?: string, + * ADDRESS_COUNTRY?: string, + * ADDRESS_COUNTRY_CODE?: string, + * ADDRESS_LOC_ADDR_ID?: int, + * COMMENTS?: string, + * OPENED?: string, + * EXPORT?: string, + * HAS_PHONE?: string, + * HAS_EMAIL?: string, + * HAS_IMOL?: string, + * ASSIGNED_BY_ID?: string, + * CREATED_BY_ID?: string, + * MODIFY_BY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * COMPANY_ID?: string, + * COMPANY_IDS?: string, + * LEAD_ID?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * ORIGIN_VERSION?: string, + * FACE_ID?: int, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string, + * PHONE?: string, + * EMAIL?: string, + * WEB?: string, + * IM?: string, + * } $fields + * + * @param array{ + * REGISTER_SONET_EVENT?: string + * } $params + * + * @return AddedItemResult + * @throws BaseException + * @throws TransportException + */ + public function add(array $fields, array $params = ['REGISTER_SONET_EVENT' => 'N']): AddedItemResult + { + return new AddedItemResult( + $result = $this->core->call( + 'crm.contact.add', + [ + 'fields' => $fields, + 'params' => $params, + ] + ) + ); + } + + /** + * Deletes the specified contact and all the associated objects. + * + * @link https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_delete.php + * + * @param int $contactId + * + * @return DeletedItemResult + * @throws BaseException + * @throws TransportException + */ + public function delete(int $contactId): DeletedItemResult + { + return new DeletedItemResult( + $this->core->call( + 'crm.contact.delete', + [ + 'id' => $contactId, + ] + ) + ); + } + + /** + * Returns the description of contact + * + * @link https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_fields.php + * + * @return FieldsResult + * @throws BaseException + * @throws TransportException + */ + public function fields(): FieldsResult + { + return new FieldsResult($this->core->call('crm.contact.fields')); + } + + /** + * Returns a contact by the specified contact ID + * + * @link https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_get.php + * + * @param int $contactId + * + * @return ContactResult + * @throws BaseException + * @throws TransportException + */ + public function get(int $contactId): ContactResult + { + return new ContactResult( + $this->core->call( + 'crm.contact.get', + [ + 'id' => $contactId, + ] + ) + ); + } + + /** + * Returns a list of contacts selected by the filter specified as the parameter. See the example for the filter notation. + * + * @link https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_list.php + * + * @param array{ + * ID?: int, + * HONORIFIC?: string, + * NAME?: string, + * SECOND_NAME?: string, + * LAST_NAME?: string, + * PHOTO?: string, + * BIRTHDATE?: string, + * TYPE_ID?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: string, + * POST?: string, + * ADDRESS?: string, + * ADDRESS_2?: string, + * ADDRESS_CITY?: string, + * ADDRESS_POSTAL_CODE?: string, + * ADDRESS_REGION?: string, + * ADDRESS_PROVINCE?: string, + * ADDRESS_COUNTRY?: string, + * ADDRESS_COUNTRY_CODE?: string, + * ADDRESS_LOC_ADDR_ID?: int, + * COMMENTS?: string, + * OPENED?: string, + * EXPORT?: string, + * HAS_PHONE?: string, + * HAS_EMAIL?: string, + * HAS_IMOL?: string, + * ASSIGNED_BY_ID?: string, + * CREATED_BY_ID?: string, + * MODIFY_BY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * COMPANY_ID?: string, + * COMPANY_IDS?: string, + * LEAD_ID?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * ORIGIN_VERSION?: string, + * FACE_ID?: int, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string, + * PHONE?: string, + * EMAIL?: string, + * WEB?: string, + * IM?: string, + * } $order + * + * @param array{ + * ID?: int, + * HONORIFIC?: string, + * NAME?: string, + * SECOND_NAME?: string, + * LAST_NAME?: string, + * PHOTO?: string, + * BIRTHDATE?: string, + * TYPE_ID?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: string, + * POST?: string, + * ADDRESS?: string, + * ADDRESS_2?: string, + * ADDRESS_CITY?: string, + * ADDRESS_POSTAL_CODE?: string, + * ADDRESS_REGION?: string, + * ADDRESS_PROVINCE?: string, + * ADDRESS_COUNTRY?: string, + * ADDRESS_COUNTRY_CODE?: string, + * ADDRESS_LOC_ADDR_ID?: int, + * COMMENTS?: string, + * OPENED?: string, + * EXPORT?: string, + * HAS_PHONE?: string, + * HAS_EMAIL?: string, + * HAS_IMOL?: string, + * ASSIGNED_BY_ID?: string, + * CREATED_BY_ID?: string, + * MODIFY_BY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * COMPANY_ID?: string, + * COMPANY_IDS?: string, + * LEAD_ID?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * ORIGIN_VERSION?: string, + * FACE_ID?: int, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string, + * PHONE?: string, + * EMAIL?: string, + * WEB?: string, + * IM?: string, + * } $filter + * @param array $select = ['ID','HONORIFIC','NAME','SECOND_NAME','LAST_NAME','PHOTO','BIRTHDATE','TYPE_ID','SOURCE_ID','SOURCE_DESCRIPTION','POST','ADDRESS','ADDRESS_2','ADDRESS_CITY','ADDRESS_POSTAL_CODE','ADDRESS_REGION','ADDRESS_PROVINCE','ADDRESS_COUNTRY','ADDRESS_COUNTRY_CODE','ADDRESS_LOC_ADDR_ID','COMMENTS','OPENED','EXPORT','HAS_PHONE','HAS_EMAIL','HAS_IMOL','ASSIGNED_BY_ID','CREATED_BY_ID','MODIFY_BY_ID','DATE_CREATE','DATE_MODIFY','COMPANY_ID','COMPANY_IDS','LEAD_ID','ORIGINATOR_ID','ORIGIN_ID','ORIGIN_VERSION','FACE_ID','UTM_SOURCE','UTM_MEDIUM','UTM_CAMPAIGN','UTM_CONTENT','UTM_TERM','PHONE','EMAIL','WEB','IM'] + * @param int $start + * + * @return ContactsResult + * @throws BaseException + * @throws TransportException + */ + public function list(array $order, array $filter, array $select, int $start): ContactsResult + { + return new ContactsResult( + $this->core->call( + 'crm.contact.list', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $start, + ] + ) + ); + } + + /** + * @param int $contactId + * @param array{ + * ID?: int, + * HONORIFIC?: string, + * NAME?: string, + * SECOND_NAME?: string, + * LAST_NAME?: string, + * PHOTO?: string, + * BIRTHDATE?: string, + * TYPE_ID?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: string, + * POST?: string, + * ADDRESS?: string, + * ADDRESS_2?: string, + * ADDRESS_CITY?: string, + * ADDRESS_POSTAL_CODE?: string, + * ADDRESS_REGION?: string, + * ADDRESS_PROVINCE?: string, + * ADDRESS_COUNTRY?: string, + * ADDRESS_COUNTRY_CODE?: string, + * ADDRESS_LOC_ADDR_ID?: int, + * COMMENTS?: string, + * OPENED?: string, + * EXPORT?: string, + * HAS_PHONE?: string, + * HAS_EMAIL?: string, + * HAS_IMOL?: string, + * ASSIGNED_BY_ID?: string, + * CREATED_BY_ID?: string, + * MODIFY_BY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * COMPANY_ID?: string, + * COMPANY_IDS?: string, + * LEAD_ID?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * ORIGIN_VERSION?: string, + * FACE_ID?: int, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string, + * PHONE?: string, + * EMAIL?: string, + * WEB?: string, + * IM?: string, + * } $fields + * + * @param array{ + * REGISTER_SONET_EVENT?: string + * } $params + * + * @return UpdatedItemResult + * @throws BaseException + * @throws TransportException + */ + public function update(int $contactId, array $fields, array $params): UpdatedItemResult + { + return new UpdatedItemResult( + $this->core->call( + 'crm.contact.update', + [ + 'id' => $contactId, + 'fields' => $fields, + 'params' => $params, + ] + ) + ); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Contacts/Service/Contacts.php b/src/Services/CRM/Contacts/Service/Contacts.php deleted file mode 100644 index bcee785b..00000000 --- a/src/Services/CRM/Contacts/Service/Contacts.php +++ /dev/null @@ -1,206 +0,0 @@ -log->debug( - 'getTraversableList.start', - [ - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'limit' => $limit, - ] - ); - - $result = $this->batch->getTraversableList('crm.contact.list', $order, $filter, $select, $limit); - - $this->log->debug('getTraversableList.finish'); - - return $result; - } - - /** - * @param array $fields - * @param array $params - * - * @return Response - * @throws BaseException - * @throws TransportException - */ - public function add(array $fields, array $params): Response - { - $this->log->debug( - 'add.start', - [ - 'fields' => $fields, - 'params' => $params, - ] - ); - - $result = $this->core->call( - 'crm.contact.add', - [ - 'fields' => $fields, - 'params' => $params, - ] - ); - - - $this->log->debug('add.finish'); - - return $result; - } - - /** - * @param int $contactId - * - * @return Response - * @throws BaseException - * @throws TransportException - */ - public function get(int $contactId): Response - { - $this->log->debug( - 'get.start', - [ - 'contactId' => $contactId, - ] - ); - $result = $this->core->call( - 'crm.contact.get', - [ - 'id' => $contactId, - ] - ); - - $this->log->debug('get.finish'); - - return $result; - } - - /** - * @param array $order - * @param array $filter - * @param array $select - * @param int $start - * - * @return Response - * @throws BaseException - * @throws TransportException - */ - public function list(array $order, array $filter, array $select, int $start): Response - { - $this->log->debug( - 'list.start', - [ - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'start' => $start, - ] - ); - - $result = $this->core->call( - 'crm.contact.list', - [ - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'start' => $start, - ] - ); - - $this->log->debug('list.finish'); - - return $result; - } - - /** - * @param int $contactId - * @param array $fields - * @param array $params - * - * @return Response - * @throws BaseException - * @throws TransportException - */ - public function update(int $contactId, array $fields, array $params): Response - { - $this->log->debug( - 'update.start', - [ - 'id' => $contactId, - 'fields' => $fields, - 'params' => $params, - ] - ); - - $result = $this->core->call( - 'crm.contact.update', - [ - 'id' => $contactId, - 'fields' => $fields, - 'params' => $params, - ] - ); - - $this->log->debug('update.finish'); - - return $result; - } - - /** - * @param int $contactId - * - * @return Response - * @throws BaseException - * @throws TransportException - */ - public function delete(int $contactId): Response - { - $this->log->debug( - 'delete.start', - [ - 'contactId' => $contactId, - ] - ); - - $result = $this->core->call( - 'crm.contact.delete', - [ - 'id' => $contactId, - ] - ); - - - $this->log->debug('delete.finish'); - - return $result; - } -} \ 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 new file mode 100644 index 00000000..5774bd92 --- /dev/null +++ b/tests/Integration/Services/CRM/Contact/Service/ContactTest.php @@ -0,0 +1,94 @@ +contactService->add(['NAME' => 'test contact'])->getId()); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers Contact::delete + */ + public function testDelete(): void + { + self::assertTrue($this->contactService->delete($this->contactService->add(['NAME' => 'test contact'])->getId())->isSuccess()); + } + + /** + * @covers Contact::fields + * @throws BaseException + * @throws TransportException + */ + public function testFields(): void + { + self::assertIsArray($this->contactService->fields()->getFieldsDescription()); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers Contact::get + */ + public function testGet(): void + { + self::assertGreaterThan( + 1, + $this->contactService->get($this->contactService->add(['NAME' => 'test contact'])->getId())->contact()->ID + ); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers Contact::list + */ + public function testList(): void + { + $this->contactService->add(['NAME' => 'test contact']); + self::assertGreaterThanOrEqual(1, $this->contactService->list([''], [''], ['ID', 'NAME'], 0)->contacts()); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers Contact::update + */ + public function testUpdate(): void + { + $deal = $this->contactService->add(['NAME' => 'test']); + $newName = 'test2'; + + self::assertTrue($this->contactService->update($deal->getId(), ['NAME' => $newName], [])->isSuccess()); + self::assertEquals($newName, $this->contactService->get($deal->getId())->contact()->NAME); + } + + public function setUp(): void + { + $this->contactService = Fabric::getServiceBuilder()->getCRMScope()->contact(); + } +} \ No newline at end of file From 24cfd4d66ddd10d249d61c3734a118e174654713 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 16 Jan 2021 16:09:17 +0300 Subject: [PATCH 198/647] add contact entity --- .../CRM/Contact/Result/ContactsResult.php | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/Services/CRM/Contact/Result/ContactsResult.php diff --git a/src/Services/CRM/Contact/Result/ContactsResult.php b/src/Services/CRM/Contact/Result/ContactsResult.php new file mode 100644 index 00000000..3a147f1c --- /dev/null +++ b/src/Services/CRM/Contact/Result/ContactsResult.php @@ -0,0 +1,31 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { + $res[] = new ContactItemResult($item); + } + + return $res; + } +} \ No newline at end of file From ccea0f3c6447c33c32e84844fb8efbc0d91520fd Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 17 Jan 2021 00:51:56 +0300 Subject: [PATCH 199/647] add contact batch mode --- README.md | 8 +- composer.json | 1 + src/Core/Batch.php | 214 +++++++++++++++++- src/Core/Contracts/BatchInterface.php | 12 +- src/Services/AbstractBatchService.php | 31 +++ src/Services/CRM/Contact/Service/Batch.php | 199 ++++++++++++++-- .../CRM/Contact/Service/ContactTest.php | 35 ++- tests/Unit/Stubs/NullBatch.php | 30 +++ tests/Unit/Stubs/NullCore.php | 31 +++ 9 files changed, 530 insertions(+), 31 deletions(-) create mode 100644 src/Services/AbstractBatchService.php create mode 100644 tests/Unit/Stubs/NullBatch.php create mode 100644 tests/Unit/Stubs/NullCore.php diff --git a/README.md b/README.md index e82d3362..8d5f45a9 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ Core DTO ### Example -### Installation +### Installation Add `"mesilov/bitrix24-php-sdk": "2.x"` to `composer.json` of your application. Or clone repo to your project. @@ -116,9 +116,8 @@ See also the list of [contributors](https://github.com/mesilov/bitrix24-php-sdk/ ### Need custom Bitrix24 application? ## email: -### Sponsors - +### Sponsors ## Русский @@ -127,7 +126,8 @@ email: - хороший DX (Developer Experience) - автодополнение методов на уровне IDE - типизированные сигнатуры вызова методов - - типизированные результаты вызова методов - используются нативные типы: int, array, bool, string + - типизированные результаты вызова методов – используются нативные типы: int, array, bool, string + - хелперы для типовых операций - хорошая документация - документация по работе конкретного метода содержащая ссылку на офф документацию - документация по работе с SDK diff --git a/composer.json b/composer.json index 4d3b7c15..43145cce 100644 --- a/composer.json +++ b/composer.json @@ -23,6 +23,7 @@ "psr/log": "1.1.3", "fig/http-message-util": "1.1.*", "symfony/http-client": "5.2.*", + "symfony/http-client-contracts": "5.2.*", "symfony/event-dispatcher": "5.2.*", "ramsey/uuid": "^3.9.3" }, diff --git a/src/Core/Batch.php b/src/Core/Batch.php index 1570d4e2..88b042ef 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -58,6 +58,49 @@ public function clearCommands(): void $this->log->debug('clearCommands.finish'); } + /** + * add entity items with batch call + * + * @param string $apiMethod + * @param array $entityItems + * + * @return Generator + * @throws BaseException + */ + public function addEntityItems(string $apiMethod, array $entityItems): Generator + { + $this->log->debug( + 'addEntityItems.start', + [ + 'apiMethod' => $apiMethod, + 'entityItems' => $entityItems, + ] + ); + + try { + $this->clearCommands(); + foreach ($entityItems as $cnt => $item) { + $this->addCommand($apiMethod, $item); + } + + foreach ($this->getTraversable(true) as $cnt => $addedItemResult) { + yield $cnt => $addedItemResult; + } + } catch (\Throwable $exception) { + $errorMessage = sprintf('batch add entity items: %s', $exception->getMessage()); + $this->log->error( + $errorMessage, + [ + 'trace' => $exception->getTrace(), + ] + ); + + throw new BaseException($errorMessage, $exception->getCode(), $exception); + } + + $this->log->debug('addEntityItems.finish'); + } + /** * add api command to commands collection for batch calls * @@ -93,6 +136,175 @@ public function addCommand( ); } + /** + * @param array $order + * + * @return array|string[] + */ + protected function getReverseOrder(array $order): array + { + $this->log->debug( + 'getReverseOrder.start', + [ + 'order' => $order, + ] + ); + $reverseOrder = null; + + if ($order === []) { + $reverseOrder = ['ID' => 'DESC']; + } + + $order = array_change_key_case($order, CASE_UPPER); + $oldDirection = array_values($order)[0]; + if ($oldDirection === 'ASC') { + $newOrderDirection = 'DESC'; + } else { + $newOrderDirection = 'ASC'; + } + $reverseOrder[array_key_first($order)] = $newOrderDirection; + + $this->log->debug( + 'getReverseOrder.finish', + [ + 'order' => $reverseOrder, + ] + ); + + return $reverseOrder; + } + + /** + * WORK IN PROGRESS + * + * @param string $apiMethod + * @param array $order + * @param array $filter + * @param array $select + * @param int|null $limit + * + * @return Generator + * @throws BaseException + * @throws Exceptions\TransportException + * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + */ + public function getTraversableListWithoutCount( + string $apiMethod, + array $order, + array $filter, + array $select, + ?int $limit = null + ): Generator { + $this->log->debug( + 'getTraversableListWithoutCount.start', + [ + 'apiMethod' => $apiMethod, + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'limit' => $limit, + ] + ); + $this->clearCommands(); + + if (!in_array('ID', $select, true)) { + $select[] = 'ID'; + } + // get total elements count + $firstResult = $this->core->call( + $apiMethod, + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => 0, + ] + ); + $nextItem = $firstResult->getResponseData()->getPagination()->getNextItem(); + $total = $firstResult->getResponseData()->getPagination()->getTotal(); + $this->log->debug( + 'getTraversableListWithoutCount.calculateCommandsRange', + [ + 'totalItems' => $total, + ] + ); + + if ($total > self::MAX_ELEMENTS_IN_PAGE && $nextItem !== null) { + //more than one page in results - register list commands + $reverseOrder = $this->getReverseOrder($order); + $firstId = $firstResult->getResponseData()->getResult()->getResultData()[0]['ID']; + + $lastId = $this->core->call( + $apiMethod, + [ + 'order' => $reverseOrder, + 'filter' => $filter, + 'select' => $select, + 'start' => 0, + ] + )->getResponseData()->getResult()->getResultData()[0]['ID']; + + //more than one page in results - register list commands + for ($startId = $firstId; $startId <= $lastId; $startId += self::MAX_ELEMENTS_IN_PAGE) { + $this->addCommand( + $apiMethod, + [ + 'order' => [], + 'filter' => ['>=ID' => $startId], + 'select' => $select, + 'start' => -1, + ] + ); + } + + $this->log->debug( + 'getTraversableList.commandsRegistered', + [ + 'commandsCount' => $this->commands->count(), + 'totalItemsToSelect' => $total, + ] + ); + + // iterate batch queries, max: 50 results per 50 elements in each result + $elementsCounter = 0; + foreach ($this->getTraversable(true) as $queryCnt => $queryResultData) { + /** + * @var $queryResultData ResponseData + */ + $this->log->debug( + 'getTraversableList.batchResultItem', + [ + 'batchCommandItemNumber' => $queryCnt, + 'nextItem' => $queryResultData->getPagination()->getNextItem(), + 'durationTime' => $queryResultData->getTime()->getDuration(), + ] + ); + // iterate items in batch query result + foreach ($queryResultData->getResult()->getResultData() as $cnt => $listElement) { + $elementsCounter++; + if ($limit !== null && $elementsCounter > $limit) { + return; + } + yield $listElement; + } + } + } else { + // one page in results + $this->addCommand( + $apiMethod, + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => 0, + ] + ); + } + } + /** * batch wrapper for *.list methods * @@ -215,7 +427,7 @@ public function getTraversableList(string $apiMethod, array $order, array $filte /** * @param bool $isHaltOnError * - * @return Generator + * @return Generator * @throws BaseException * @throws Exceptions\TransportException * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface diff --git a/src/Core/Contracts/BatchInterface.php b/src/Core/Contracts/BatchInterface.php index c9bee7a2..953f1fd4 100644 --- a/src/Core/Contracts/BatchInterface.php +++ b/src/Core/Contracts/BatchInterface.php @@ -5,6 +5,7 @@ namespace Bitrix24\SDK\Core\Contracts; use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Response\DTO\ResponseData; use Generator; /** @@ -14,7 +15,6 @@ */ interface BatchInterface { - /** * batch wrapper for *.list methods * @@ -28,4 +28,14 @@ interface BatchInterface * @throws BaseException */ public function getTraversableList(string $apiMethod, array $order, array $filter, array $select, ?int $limit = null): Generator; + + /** + * batch wrapper for *.add methods + * + * @param string $apiMethod + * @param array $entityItems + * + * @return Generator + */ + public function addEntityItems(string $apiMethod, array $entityItems): Generator; } \ No newline at end of file diff --git a/src/Services/AbstractBatchService.php b/src/Services/AbstractBatchService.php new file mode 100644 index 00000000..c3d30071 --- /dev/null +++ b/src/Services/AbstractBatchService.php @@ -0,0 +1,31 @@ +batch = $batch; + $this->log = $log; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Contact/Service/Batch.php b/src/Services/CRM/Contact/Service/Batch.php index e39e7815..9eceb42a 100644 --- a/src/Services/CRM/Contact/Service/Batch.php +++ b/src/Services/CRM/Contact/Service/Batch.php @@ -4,47 +4,130 @@ namespace Bitrix24\SDK\Services\CRM\Contact\Service; -use Bitrix24\SDK\Core\Contracts\BatchInterface; use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Services\AbstractBatchService; use Bitrix24\SDK\Services\CRM\Contact\Result\ContactItemResult; use Generator; -use Psr\Log\LoggerInterface; /** * Class Batch * * @package Bitrix24\SDK\Services\CRM\Contact\Service */ -class Batch +class Batch extends AbstractBatchService { - protected BatchInterface $batch; - protected LoggerInterface $log; - /** - * Batch constructor. + * batch list method * - * @param BatchInterface $batch - * @param LoggerInterface $log - */ - public function __construct(BatchInterface $batch, LoggerInterface $log) - { - $this->batch = $batch; - $this->log = $log; - } - - /** - * @param array $order - * @param array $filter - * @param array $select + * @param array{ + * ID?: int, + * HONORIFIC?: string, + * NAME?: string, + * SECOND_NAME?: string, + * LAST_NAME?: string, + * PHOTO?: string, + * BIRTHDATE?: string, + * TYPE_ID?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: string, + * POST?: string, + * ADDRESS?: string, + * ADDRESS_2?: string, + * ADDRESS_CITY?: string, + * ADDRESS_POSTAL_CODE?: string, + * ADDRESS_REGION?: string, + * ADDRESS_PROVINCE?: string, + * ADDRESS_COUNTRY?: string, + * ADDRESS_COUNTRY_CODE?: string, + * ADDRESS_LOC_ADDR_ID?: int, + * COMMENTS?: string, + * OPENED?: string, + * EXPORT?: string, + * HAS_PHONE?: string, + * HAS_EMAIL?: string, + * HAS_IMOL?: string, + * ASSIGNED_BY_ID?: string, + * CREATED_BY_ID?: string, + * MODIFY_BY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * COMPANY_ID?: string, + * COMPANY_IDS?: string, + * LEAD_ID?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * ORIGIN_VERSION?: string, + * FACE_ID?: int, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string, + * PHONE?: string, + * EMAIL?: string, + * WEB?: string, + * IM?: string, + * } $order + * + * @param array{ + * ID?: int, + * HONORIFIC?: string, + * NAME?: string, + * SECOND_NAME?: string, + * LAST_NAME?: string, + * PHOTO?: string, + * BIRTHDATE?: string, + * TYPE_ID?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: string, + * POST?: string, + * ADDRESS?: string, + * ADDRESS_2?: string, + * ADDRESS_CITY?: string, + * ADDRESS_POSTAL_CODE?: string, + * ADDRESS_REGION?: string, + * ADDRESS_PROVINCE?: string, + * ADDRESS_COUNTRY?: string, + * ADDRESS_COUNTRY_CODE?: string, + * ADDRESS_LOC_ADDR_ID?: int, + * COMMENTS?: string, + * OPENED?: string, + * EXPORT?: string, + * HAS_PHONE?: string, + * HAS_EMAIL?: string, + * HAS_IMOL?: string, + * ASSIGNED_BY_ID?: string, + * CREATED_BY_ID?: string, + * MODIFY_BY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * COMPANY_ID?: string, + * COMPANY_IDS?: string, + * LEAD_ID?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * ORIGIN_VERSION?: string, + * FACE_ID?: int, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string, + * PHONE?: string, + * EMAIL?: string, + * WEB?: string, + * IM?: string, + * } $filter + * @param array $select = ['ID','HONORIFIC','NAME','SECOND_NAME','LAST_NAME','PHOTO','BIRTHDATE','TYPE_ID','SOURCE_ID','SOURCE_DESCRIPTION','POST','ADDRESS','ADDRESS_2','ADDRESS_CITY','ADDRESS_POSTAL_CODE','ADDRESS_REGION','ADDRESS_PROVINCE','ADDRESS_COUNTRY','ADDRESS_COUNTRY_CODE','ADDRESS_LOC_ADDR_ID','COMMENTS','OPENED','EXPORT','HAS_PHONE','HAS_EMAIL','HAS_IMOL','ASSIGNED_BY_ID','CREATED_BY_ID','MODIFY_BY_ID','DATE_CREATE','DATE_MODIFY','COMPANY_ID','COMPANY_IDS','LEAD_ID','ORIGINATOR_ID','ORIGIN_ID','ORIGIN_VERSION','FACE_ID','UTM_SOURCE','UTM_MEDIUM','UTM_CAMPAIGN','UTM_CONTENT','UTM_TERM','PHONE','EMAIL','WEB','IM'] * @param int|null $limit * * @return Generator * @throws BaseException */ - public function batchList(array $order, array $filter, array $select, ?int $limit = null): Generator + public function list(array $order, array $filter, array $select, ?int $limit = null): Generator { $this->log->debug( - 'batchList', + 'list', [ 'order' => $order, 'filter' => $filter, @@ -56,4 +139,76 @@ public function batchList(array $order, array $filter, array $select, ?int $limi yield $key => new ContactItemResult($value); } } + + /** + * Batch adding contacts + * + * @param array $contacts + * + * @return Generator + */ + public function add(array $contacts): Generator + { + $items = []; + foreach ($contacts as $contact) { + $items[] = [ + 'fields' => $contact, + ]; + } + foreach ($this->batch->addEntityItems('crm.contact.add', $items) as $key => $item) { + yield $key => new ContactItemResult( + [ + 'ID' => $item->getResult()->getResultData()[0], + ] + ); + } + } } \ 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 5774bd92..afe39c07 100644 --- a/tests/Integration/Services/CRM/Contact/Service/ContactTest.php +++ b/tests/Integration/Services/CRM/Contact/Service/ContactTest.php @@ -80,11 +80,40 @@ public function testList(): void */ public function testUpdate(): void { - $deal = $this->contactService->add(['NAME' => 'test']); + $contact = $this->contactService->add(['NAME' => 'test']); $newName = 'test2'; - self::assertTrue($this->contactService->update($deal->getId(), ['NAME' => $newName], [])->isSuccess()); - self::assertEquals($newName, $this->contactService->get($deal->getId())->contact()->NAME); + self::assertTrue($this->contactService->update($contact->getId(), ['NAME' => $newName], [])->isSuccess()); + self::assertEquals($newName, $this->contactService->get($contact->getId())->contact()->NAME); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testBatchList(): void + { + $this->contactService->add(['NAME' => 'test contact']); + $cnt = 0; + + foreach ($this->contactService->batch->list([], ['>ID' => '1'], ['ID', 'NAME'], 1) as $item) { + $cnt++; + } + self::assertGreaterThanOrEqual(1, $cnt); + } + + public function testBatchAdd(): void + { + $contacts = []; + for ($i = 1; $i < 60; $i++) { + $contacts[] = ['NAME' => 'name-' . $i]; + } + $cnt = 0; + foreach ($this->contactService->batch->add($contacts) as $item) { + $cnt++; + } + + self::assertEquals(count($contacts), $cnt); } public function setUp(): void diff --git a/tests/Unit/Stubs/NullBatch.php b/tests/Unit/Stubs/NullBatch.php new file mode 100644 index 00000000..5ffdb8ef --- /dev/null +++ b/tests/Unit/Stubs/NullBatch.php @@ -0,0 +1,30 @@ + Date: Sun, 17 Jan 2021 21:22:37 +0300 Subject: [PATCH 200/647] add settings service --- .../Settings/Result/SettingsModeResult.php | 20 +++++++++++++ .../CRM/Settings/Service/Settings.php | 28 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 src/Services/CRM/Settings/Result/SettingsModeResult.php create mode 100644 src/Services/CRM/Settings/Service/Settings.php diff --git a/src/Services/CRM/Settings/Result/SettingsModeResult.php b/src/Services/CRM/Settings/Result/SettingsModeResult.php new file mode 100644 index 00000000..63996e6d --- /dev/null +++ b/src/Services/CRM/Settings/Result/SettingsModeResult.php @@ -0,0 +1,20 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Settings/Service/Settings.php b/src/Services/CRM/Settings/Service/Settings.php new file mode 100644 index 00000000..016acb63 --- /dev/null +++ b/src/Services/CRM/Settings/Service/Settings.php @@ -0,0 +1,28 @@ +core->call('crm.settings.mode.get')); + } +} \ No newline at end of file From 9788fdf471fd29fe240aafff32b315505af6bc69 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 17 Jan 2021 21:46:50 +0300 Subject: [PATCH 201/647] add deals service --- .../Deal/Result/DealCategoryItemResult.php | 20 ++ .../CRM/Deal/Result/DealCategoryResult.php | 21 ++ .../CRM/Deal/Result/DealItemResult.php | 50 ++++ src/Services/CRM/Deal/Result/DealResult.php | 21 ++ src/Services/CRM/Deal/Result/DealsResult.php | 31 +++ src/Services/CRM/Deal/Service/Batch.php | 212 +++++++++++++++ src/Services/CRM/Deal/Service/Deal.php | 252 ++++++++++++++++++ src/Services/CRM/Deals/Service/Deals.php | 139 ---------- .../Services/CRM/Deal/Service/DealTest.php | 122 +++++++++ 9 files changed, 729 insertions(+), 139 deletions(-) create mode 100644 src/Services/CRM/Deal/Result/DealCategoryItemResult.php create mode 100644 src/Services/CRM/Deal/Result/DealCategoryResult.php create mode 100644 src/Services/CRM/Deal/Result/DealItemResult.php create mode 100644 src/Services/CRM/Deal/Result/DealResult.php create mode 100644 src/Services/CRM/Deal/Result/DealsResult.php create mode 100644 src/Services/CRM/Deal/Service/Batch.php create mode 100644 src/Services/CRM/Deal/Service/Deal.php delete mode 100644 src/Services/CRM/Deals/Service/Deals.php create mode 100644 tests/Integration/Services/CRM/Deal/Service/DealTest.php diff --git a/src/Services/CRM/Deal/Result/DealCategoryItemResult.php b/src/Services/CRM/Deal/Result/DealCategoryItemResult.php new file mode 100644 index 00000000..4dd57ab7 --- /dev/null +++ b/src/Services/CRM/Deal/Result/DealCategoryItemResult.php @@ -0,0 +1,20 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData()); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealItemResult.php b/src/Services/CRM/Deal/Result/DealItemResult.php new file mode 100644 index 00000000..123ffa90 --- /dev/null +++ b/src/Services/CRM/Deal/Result/DealItemResult.php @@ -0,0 +1,50 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData()); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealsResult.php b/src/Services/CRM/Deal/Result/DealsResult.php new file mode 100644 index 00000000..2481a7dd --- /dev/null +++ b/src/Services/CRM/Deal/Result/DealsResult.php @@ -0,0 +1,31 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData() as $deal) { + $res[] = new DealItemResult($deal); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Service/Batch.php b/src/Services/CRM/Deal/Service/Batch.php new file mode 100644 index 00000000..414775fd --- /dev/null +++ b/src/Services/CRM/Deal/Service/Batch.php @@ -0,0 +1,212 @@ +batch = $batch; + $this->log = $log; + } + + /** + * batch list method for deals + * + * @param array{ + * ID?: int, + * TITLE?: string, + * TYPE_ID?: string, + * CATEGORY_ID?: string, + * STAGE_ID?: string, + * STAGE_SEMANTIC_ID?: string, + * IS_NEW?: string, + * IS_RECURRING?: string, + * IS_RETURN_CUSTOMER?: string, + * IS_REPEATED_APPROACH?: string, + * PROBABILITY?: int, + * CURRENCY_ID?: string, + * OPPORTUNITY?: string, + * IS_MANUAL_OPPORTUNITY?: string, + * TAX_VALUE?: string, + * COMPANY_ID?: string, + * CONTACT_ID?: string, + * CONTACT_IDS?: string, + * QUOTE_ID?: string, + * BEGINDATE?: string, + * CLOSEDATE?: string, + * OPENED?: string, + * CLOSED?: string, + * COMMENTS?: string, + * ASSIGNED_BY_ID?: string, + * CREATED_BY_ID?: string, + * MODIFY_BY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: string, + * LEAD_ID?: string, + * ADDITIONAL_INFO?: string, + * LOCATION_ID?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string, + * } $order + * + * @param array{ + * ID?: int, + * TITLE?: string, + * TYPE_ID?: string, + * CATEGORY_ID?: string, + * STAGE_ID?: string, + * STAGE_SEMANTIC_ID?: string, + * IS_NEW?: string, + * IS_RECURRING?: string, + * IS_RETURN_CUSTOMER?: string, + * IS_REPEATED_APPROACH?: string, + * PROBABILITY?: int, + * CURRENCY_ID?: string, + * OPPORTUNITY?: string, + * IS_MANUAL_OPPORTUNITY?: string, + * TAX_VALUE?: string, + * COMPANY_ID?: string, + * CONTACT_ID?: string, + * CONTACT_IDS?: string, + * QUOTE_ID?: string, + * BEGINDATE?: string, + * CLOSEDATE?: string, + * OPENED?: string, + * CLOSED?: string, + * COMMENTS?: string, + * ASSIGNED_BY_ID?: string, + * CREATED_BY_ID?: string, + * MODIFY_BY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: string, + * LEAD_ID?: string, + * ADDITIONAL_INFO?: string, + * LOCATION_ID?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string, + * } $filter + * @param array $select = ['ID','TITLE','TYPE_ID','CATEGORY_ID','STAGE_ID','STAGE_SEMANTIC_ID','IS_NEW','IS_RECURRING','IS_RETURN_CUSTOMER','IS_REPEATED_APPROACH','PROBABILITY','CURRENCY_ID','OPPORTUNITY','IS_MANUAL_OPPORTUNITY','TAX_VALUE','COMPANY_ID','CONTACT_ID','CONTACT_IDS','QUOTE_ID','BEGINDATE','CLOSEDATE','OPENED','CLOSED','COMMENTS','ASSIGNED_BY_ID','CREATED_BY_ID','MODIFY_BY_ID','DATE_CREATE','DATE_MODIFY','SOURCE_ID','SOURCE_DESCRIPTION','LEAD_ID','ADDITIONAL_INFO','LOCATION_ID','ORIGINATOR_ID','ORIGIN_ID','UTM_SOURCE','UTM_MEDIUM','UTM_CAMPAIGN','UTM_CONTENT','UTM_TERM'] + * @param int|null $limit + * + * @return Generator + * @throws BaseException + */ + public function list(array $order, array $filter, array $select, ?int $limit = null): Generator + { + $this->log->debug( + 'batchList', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'limit' => $limit, + ] + ); + foreach ($this->batch->getTraversableList('crm.deal.list', $order, $filter, $select, $limit) as $key => $value) { + yield $key => new DealItemResult($value); + } + } + + /** + * Batch adding deals + * + * @param array $deals + * + * @return Generator + */ + public function add(array $deals): Generator + { + $items = []; + foreach ($deals as $contact) { + $items[] = [ + 'fields' => $contact, + ]; + } + foreach ($this->batch->addEntityItems('crm.deal.add', $items) as $key => $item) { + yield $key => new DealItemResult( + [ + 'ID' => $item->getResult()->getResultData()[0], + ] + ); + } + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Service/Deal.php b/src/Services/CRM/Deal/Service/Deal.php new file mode 100644 index 00000000..c8289157 --- /dev/null +++ b/src/Services/CRM/Deal/Service/Deal.php @@ -0,0 +1,252 @@ +batch = $batch; + } + + /** + * add new deal + * + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_add.php + * + * @param array{ + * ID?: int, + * TITLE?: string, + * TYPE_ID?: string, + * CATEGORY_ID?: string, + * STAGE_ID?: string, + * STAGE_SEMANTIC_ID?: string, + * IS_NEW?: string, + * IS_RECURRING?: string, + * PROBABILITY?: string, + * CURRENCY_ID?: string, + * OPPORTUNITY?: string, + * IS_MANUAL_OPPORTUNITY?: string, + * TAX_VALUE?: string, + * LEAD_ID?: string, + * COMPANY_ID?: string, + * CONTACT_ID?: string, + * QUOTE_ID?: string, + * BEGINDATE?: string, + * CLOSEDATE?: string, + * OPENED?: string, + * CLOSED?: string, + * COMMENTS?: string, + * ADDITIONAL_INFO?: string, + * LOCATION_ID?: string, + * IS_RETURN_CUSTOMER?: string, + * IS_REPEATED_APPROACH?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string + * } $fields + * + * @param array{ + * REGISTER_SONET_EVENT?: string + * } $params + * + * @return AddedItemResult + * @throws BaseException + * @throws TransportException + */ + public function add(array $fields, array $params = []): AddedItemResult + { + return new AddedItemResult( + $this->core->call( + 'crm.deal.add', + [ + 'fields' => $fields, + 'params' => $params, + ] + ) + ); + } + + /** + * Deletes the specified deal and all the associated objects. + * + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_delete.php + * + * @param int $id + * + * @return DeletedItemResult + * @throws BaseException + * @throws TransportException + */ + public function delete(int $id): DeletedItemResult + { + return new DeletedItemResult( + $this->core->call( + 'crm.deal.delete', + [ + 'id' => $id, + ] + ) + ); + } + + /** + * Returns the description of the deal fields, including user fields. + * + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_fields.php + * + * @return FieldsResult + * @throws BaseException + * @throws TransportException + */ + public function fields(): FieldsResult + { + return new FieldsResult($this->core->call('crm.deal.fields')); + } + + /** + * Returns a deal by the deal ID. + * + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_get.php + * + * @param int $id + * + * @return DealResult + * @throws BaseException + * @throws TransportException + */ + public function get(int $id): DealResult + { + return new DealResult($this->core->call('crm.deal.get', ['id' => $id])); + } + + /** + * Get list of deal items. + * + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_list.php + * + * @param array $order - order of deal items + * @param array $filter - filter array + * @param array $select = ['ID','TITLE','TYPE_ID','CATEGORY_ID','STAGE_ID','STAGE_SEMANTIC_ID','IS_NEW','IS_RECURRING','PROBABILITY', 'CURRENCY_ID', 'OPPORTUNITY','IS_MANUAL_OPPORTUNITY','TAX_VALUE','LEAD_ID','COMPANY_ID','CONTACT_ID','QUOTE_ID','BEGINDATE','CLOSEDATE','OPENED','CLOSED','COMMENTS','ADDITIONAL_INFO','LOCATION_ID','IS_RETURN_CUSTOMER','IS_REPEATED_APPROACH','SOURCE_ID','SOURCE_DESCRIPTION','ORIGINATOR_ID','ORIGIN_ID','UTM_SOURCE','UTM_MEDIUM','UTM_CAMPAIGN','UTM_CONTENT','UTM_TERM'] + * @param integer $startItem - entity number to start from (usually returned in 'next' field of previous 'crm.deal.list' API call) + * + * @throws BaseException + * @throws TransportException + * @return DealsResult + */ + public function list(array $order, array $filter, array $select, int $startItem = 0): DealsResult + { + return new DealsResult( + $this->core->call( + 'crm.deal.list', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $startItem, + ] + ) + ); + } + + /** + * Updates the specified (existing) deal. + * + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_update.php + * + * @param int $id + * @param array{ + * ID?: int, + * TITLE?: string, + * TYPE_ID?: string, + * CATEGORY_ID?: string, + * STAGE_ID?: string, + * STAGE_SEMANTIC_ID?: string, + * IS_NEW?: string, + * IS_RECURRING?: string, + * PROBABILITY?: string, + * CURRENCY_ID?: string, + * OPPORTUNITY?: string, + * IS_MANUAL_OPPORTUNITY?: string, + * TAX_VALUE?: string, + * LEAD_ID?: string, + * COMPANY_ID?: string, + * CONTACT_ID?: string, + * QUOTE_ID?: string, + * BEGINDATE?: string, + * CLOSEDATE?: string, + * OPENED?: string, + * CLOSED?: string, + * COMMENTS?: string, + * ADDITIONAL_INFO?: string, + * LOCATION_ID?: string, + * IS_RETURN_CUSTOMER?: string, + * IS_REPEATED_APPROACH?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string + * } $fields + * + * @param array{ + * REGISTER_SONET_EVENT?: string + * } $params + * + * @return UpdatedItemResult + * @throws BaseException + * @throws TransportException + */ + public function update(int $id, array $fields, array $params): UpdatedItemResult + { + return new UpdatedItemResult( + $this->core->call( + 'crm.deal.update', + [ + 'id' => $id, + 'fields' => $fields, + 'params' => $params, + ] + ) + ); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deals/Service/Deals.php b/src/Services/CRM/Deals/Service/Deals.php deleted file mode 100644 index ff1088e6..00000000 --- a/src/Services/CRM/Deals/Service/Deals.php +++ /dev/null @@ -1,139 +0,0 @@ -log->debug( - 'getTraversableList.start', - [ - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'limit' => $limit, - ] - ); - - $result = $this->batch->getTraversableList('crm.deal.list', $order, $filter, $select, $limit); - - $this->log->debug('getTraversableList.finish'); - - return $result; - } - - /** - * Get list of deal items. - * - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_list.php - * - * @param array $order - order of deal items - * @param array $filter - filter array - * @param array $select - array of collumns to select - * @param integer $startItem - entity number to start from (usually returned in 'next' field of previous 'crm.deal.list' API call) - * - * @return Response - */ - public function list(array $order, array $filter, array $select, int $startItem = 0): Response - { - $this->log->debug( - 'deals.list.start', - [ - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'start' => $startItem, - ] - ); - - $result = $this->core->call( - 'crm.deal.list', - [ - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'start' => $startItem, - ] - ); - $this->log->debug('deals.list.finish'); - - return $result; - } - - /** - * @param array $fields - * @param array $params - * - * @return Response - * @throws BaseException - * @throws TransportException - */ - public function add(array $fields, array $params = []): Response - { - $this->log->debug( - 'add.start', - [ - 'fields' => $fields, - 'params' => $params, - ] - ); - - $result = $this->core->call( - 'crm.deal.add', - [ - 'fields' => $fields, - 'params' => $params, - ] - ); - - $this->log->debug('add.finish'); - - return $result; - } - - /** - * @param int $id - * - * @return Response - * @throws BaseException - * @throws TransportException - */ - public function get(int $id): Response - { - $this->log->debug( - 'get.start', - [ - 'id' => $id, - ] - ); - - $response = $this->core->call('crm.deal.get', ['id' => $id]); - - $this->log->debug('get.finish'); - - return $response; - } -} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Deal/Service/DealTest.php b/tests/Integration/Services/CRM/Deal/Service/DealTest.php new file mode 100644 index 00000000..356183fa --- /dev/null +++ b/tests/Integration/Services/CRM/Deal/Service/DealTest.php @@ -0,0 +1,122 @@ +dealService->add(['TITLE' => 'test deal'])->getId()); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers Deal::delete + */ + public function testDelete(): void + { + self::assertTrue($this->dealService->delete($this->dealService->add(['TITLE' => 'test deal'])->getId())->isSuccess()); + } + + /** + * @covers Deal::fields + * @throws BaseException + * @throws TransportException + */ + public function testFields(): void + { + self::assertIsArray($this->dealService->fields()->getFieldsDescription()); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers Deal::get + */ + public function testGet(): void + { + self::assertGreaterThan( + 1, + $this->dealService->get($this->dealService->add(['TITLE' => 'test deal'])->getId())->deal()->ID + ); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers Deal::list + */ + public function testList(): void + { + $this->dealService->add(['TITLE' => 'test']); + self::assertGreaterThanOrEqual(1, $this->dealService->list([], [], ['ID', 'TITLE', 'TYPE_ID'])->getDeals()); + } + + public function testUpdate(): void + { + $deal = $this->dealService->add(['TITLE' => 'test']); + $newTitle = 'test2'; + + self::assertTrue($this->dealService->update($deal->getId(), ['TITLE' => $newTitle], [])->isSuccess()); + self::assertEquals($newTitle, $this->dealService->get($deal->getId())->deal()->TITLE); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Contact\Service\Batch::list() + * @throws BaseException + * @throws TransportException + */ + public function testBatchList(): void + { + $this->dealService->add(['TITLE' => 'test deal']); + $cnt = 0; + + foreach ($this->dealService->batch->list([], ['>ID' => '1'], ['ID', 'NAME'], 1) as $item) { + $cnt++; + } + self::assertGreaterThanOrEqual(1, $cnt); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\Batch::add() + */ + public function testBatchAdd(): void + { + $deals = []; + for ($i = 1; $i < 60; $i++) { + $deals[] = ['TITLE' => 'TITLE-' . $i]; + } + $cnt = 0; + foreach ($this->dealService->batch->add($deals) as $item) { + $cnt++; + } + + self::assertEquals(count($deals), $cnt); + } + + public function setUp(): void + { + $this->dealService = Fabric::getServiceBuilder()->getCRMScope()->deal(); + } +} \ No newline at end of file From 9c4d69876bb783bd7545d12bf057e4832563fb64 Mon Sep 17 00:00:00 2001 From: Denis Waleev Date: Wed, 27 Jan 2021 10:26:26 +0500 Subject: [PATCH 202/647] Change version of symfony/http-client-contracts to ^2.1 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 43145cce..4b1139ce 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "psr/log": "1.1.3", "fig/http-message-util": "1.1.*", "symfony/http-client": "5.2.*", - "symfony/http-client-contracts": "5.2.*", + "symfony/http-client-contracts": "^2.1", "symfony/event-dispatcher": "5.2.*", "ramsey/uuid": "^3.9.3" }, From 4dfde34a10ed33723add5756a0f0ab600b9c7b55 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 30 Jan 2021 18:15:54 +0300 Subject: [PATCH 203/647] remove travice ci and add github actions --- .github/workflows/ci.yml | 19 +++++++++++++++++++ .travis.yml | 21 --------------------- phpunit.xml.dist | 7 +++---- 3 files changed, 22 insertions(+), 25 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..cfe7ba7a --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,19 @@ +name: CI + +on: [push] + +jobs: + build-test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - uses: php-actions/composer@dynamic-docker + + - name: PHPUnit Tests + uses: php-actions/phpunit@dynamic-docker + with: + bootstrap: vendor/autoload.php + configuration: phpunit.xml.dist + args: --coverage-text \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 73edc3d5..00000000 --- a/.travis.yml +++ /dev/null @@ -1,21 +0,0 @@ -language: php - -php: - - 7.1 - - 7.2 - - 7.3 - - 7.4 - -sudo: false - -cache: - directories: - - vendor - - $HOME/.composer/cache - -before_script: - - composer self-update - - composer install --no-interaction --prefer-source --dev - -script: - composer test diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 702c2300..3d33e504 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -5,8 +5,7 @@ colors="true" bootstrap="vendor/autoload.php" failOnRisky="true" - failOnWarning="true" -> + failOnWarning="true"> ./src @@ -16,8 +15,8 @@ - - ./tests/ + + ./tests/Unit
From 4d26c088a7f767cdebc4df3c976160ac3fe38b81 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 30 Jan 2021 18:35:18 +0300 Subject: [PATCH 204/647] fix errors --- .github/workflows/ci.yml | 27 ++++++++++++++++++--------- composer.json | 2 +- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cfe7ba7a..8b450adf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,19 +1,28 @@ -name: CI +name: PHP Unit tests -on: [push] +on: [ push ] jobs: - build-test: + build: + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: php-actions/composer@dynamic-docker + - name: Validate composer.json and composer.lock + run: composer validate - - name: PHPUnit Tests - uses: php-actions/phpunit@dynamic-docker + - name: Cache Composer packages + id: composer-cache + uses: actions/cache@v2 with: - bootstrap: vendor/autoload.php - configuration: phpunit.xml.dist - args: --coverage-text \ No newline at end of file + path: vendor + key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-php- + - name: Install dependencies + if: steps.composer-cache.outputs.cache-hit != 'true' + run: composer install --prefer-dist --no-progress --no-suggest + - name: Run test suite + run: composer run-script unit-tests \ No newline at end of file diff --git a/composer.json b/composer.json index 43145cce..3c3e3d93 100644 --- a/composer.json +++ b/composer.json @@ -48,7 +48,7 @@ } }, "scripts": { - "test": [ + "unit-tests": [ "phpunit --colors=always --verbose" ] } From 8e4f2eca71e35941760d30ffb73ffea1e12d6198 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 30 Jan 2021 18:46:16 +0300 Subject: [PATCH 205/647] fix errors 2 --- .github/workflows/ci.yml | 58 +++++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8b450adf..2f5ad9ed 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,28 +1,56 @@ -name: PHP Unit tests +name: "Continuous Integration" -on: [ push ] +on: + - push + - pull_request + +env: + COMPOSER_FLAGS: "--ansi --no-interaction --no-progress --prefer-dist" jobs: - build: + tests: + name: "CI" runs-on: ubuntu-latest + strategy: + matrix: + php-version: + - "7.4" + - "8.0" + - "8.1" + dependencies: [highest] + include: + - php-version: "8.0" + dependencies: lowest + steps: - - uses: actions/checkout@v2 + - name: "Checkout" + uses: "actions/checkout@v2" + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + coverage: "none" + php-version: "${{ matrix.php-version }}" - - name: Validate composer.json and composer.lock - run: composer validate + - name: Get composer cache directory + id: composercache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - name: Cache Composer packages - id: composer-cache + - name: Cache dependencies uses: actions/cache@v2 with: - path: vendor - key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} - restore-keys: | - ${{ runner.os }}-php- - - name: Install dependencies - if: steps.composer-cache.outputs.cache-hit != 'true' - run: composer install --prefer-dist --no-progress --no-suggest + path: ${{ steps.composercache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + + - name: "Install latest dependencies" + run: | + composer update ${{ env.COMPOSER_FLAGS }} + + - name: "Run tests" + run: "composer exec phpunit -- --verbose" + - name: Run test suite run: composer run-script unit-tests \ No newline at end of file From a8fdfc3d85036406ab0e890123a524ae4900e37e Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 30 Jan 2021 18:51:20 +0300 Subject: [PATCH 206/647] fix errors 3 --- .github/workflows/ci.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2f5ad9ed..a71500dc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,9 +20,6 @@ jobs: - "8.0" - "8.1" dependencies: [highest] - include: - - php-version: "8.0" - dependencies: lowest steps: - name: "Checkout" @@ -45,7 +42,7 @@ jobs: key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} restore-keys: ${{ runner.os }}-composer- - - name: "Install latest dependencies" + - name: "Install dependencies" run: | composer update ${{ env.COMPOSER_FLAGS }} From b8bc571d22c31066b40e17f50f213f028b4fece8 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 30 Jan 2021 18:59:09 +0300 Subject: [PATCH 207/647] fix errors 4 --- .github/workflows/ci.yml | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a71500dc..147f70c1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,8 +17,6 @@ jobs: matrix: php-version: - "7.4" - - "8.0" - - "8.1" dependencies: [highest] steps: @@ -31,17 +29,6 @@ jobs: coverage: "none" php-version: "${{ matrix.php-version }}" - - name: Get composer cache directory - id: composercache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Cache dependencies - uses: actions/cache@v2 - with: - path: ${{ steps.composercache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} - restore-keys: ${{ runner.os }}-composer- - - name: "Install dependencies" run: | composer update ${{ env.COMPOSER_FLAGS }} From 470f30b691f3ad7978e857fe38b48cdd9ea397b9 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 31 Jan 2021 00:29:50 +0300 Subject: [PATCH 208/647] add deal category --- .../CRM/Deal/Result/DealCategoriesResult.php | 31 +++ .../Deal/Result/DealCategoryStatusResult.php | 26 ++ .../CRM/Deal/Service/DealCategory.php | 228 ++++++++++++++++ .../CRM/Deals/Service/DealCategory.php | 245 ------------------ .../CRM/Deal/Service/DealCategoryTest.php | 163 ++++++++++++ 5 files changed, 448 insertions(+), 245 deletions(-) create mode 100644 src/Services/CRM/Deal/Result/DealCategoriesResult.php create mode 100644 src/Services/CRM/Deal/Result/DealCategoryStatusResult.php create mode 100644 src/Services/CRM/Deal/Service/DealCategory.php delete mode 100644 src/Services/CRM/Deals/Service/DealCategory.php create mode 100644 tests/Integration/Services/CRM/Deal/Service/DealCategoryTest.php diff --git a/src/Services/CRM/Deal/Result/DealCategoriesResult.php b/src/Services/CRM/Deal/Result/DealCategoriesResult.php new file mode 100644 index 00000000..f8d8eee5 --- /dev/null +++ b/src/Services/CRM/Deal/Result/DealCategoriesResult.php @@ -0,0 +1,31 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData() as $dealCategory) { + $res[] = new DealCategoryItemResult($dealCategory); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealCategoryStatusResult.php b/src/Services/CRM/Deal/Result/DealCategoryStatusResult.php new file mode 100644 index 00000000..68ea8e06 --- /dev/null +++ b/src/Services/CRM/Deal/Result/DealCategoryStatusResult.php @@ -0,0 +1,26 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Service/DealCategory.php b/src/Services/CRM/Deal/Service/DealCategory.php new file mode 100644 index 00000000..bdda858d --- /dev/null +++ b/src/Services/CRM/Deal/Service/DealCategory.php @@ -0,0 +1,228 @@ +core->call( + 'crm.dealcategory.add', + [ + 'fields' => $fields, + ] + ) + ); + } + + /** + * Deletes a deal category. + * + * @link https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_delete.php + * + * @param int $categoryId + * + * @return DeletedItemResult + * @throws BaseException + * @throws TransportException + */ + public function delete(int $categoryId): DeletedItemResult + { + return new DeletedItemResult( + $this->core->call( + 'crm.dealcategory.delete', + [ + 'id' => $categoryId, + ] + ) + ); + } + + /** + * Returns field description for deal categories. + * + * @link https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_fields.php + * + * @return FieldsResult + * @throws BaseException + * @throws TransportException + */ + public function fields(): FieldsResult + { + return new FieldsResult($this->core->call('crm.dealcategory.fields')); + } + + /** + * The method reads settings for general deal category + * + * @link https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_default_get.php + * @return DealCategoryResult + * @throws BaseException + * @throws TransportException + */ + public function getDefaultCategorySettings(): DealCategoryResult + { + return new DealCategoryResult($this->core->call('crm.dealcategory.default.get')); + } + + /** + * The method writes settings for general deal category. + * + * @link https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_default_set.php + * + * @param array{ + * NAME?: string, + * } $parameters + * + * @return UpdatedItemResult + * @throws BaseException + * @throws TransportException + */ + public function setDefaultCategorySettings(array $parameters): UpdatedItemResult + { + return new UpdatedItemResult($this->core->call('crm.dealcategory.default.set', $parameters)); + } + + + /** + * Returns deal category by the ID + * + * @link https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_get.php + * + * @param int $categoryId + * + * @return DealCategoryResult + * @throws BaseException + * @throws TransportException + */ + public function get(int $categoryId): DealCategoryResult + { + return new DealCategoryResult( + $this->core->call( + 'crm.dealcategory.get', + [ + 'id' => $categoryId, + ] + ) + ); + } + + /** + * Returns a list of deal categories by the filter. Is the implementation of list method for deal categories. + * + * @link https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_list.php + * + * @param array $order + * @param array $filter + * @param array $select + * @param int $start + * + * @return DealCategoriesResult + * @throws BaseException + * @throws TransportException + */ + public function list(array $order, array $filter, array $select, int $start): DealCategoriesResult + { + return new DealCategoriesResult( + $this->core->call( + 'crm.dealcategory.list', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $start, + ] + ) + ); + } + + /** + * Returns directory type ID for storage deal categories by the ID. + * + * @link https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_status.php + * + * @param int $categoryId + * + * @return DealCategoryStatusResult + * @throws BaseException + * @throws TransportException + */ + public function getStatus(int $categoryId): DealCategoryStatusResult + { + return new DealCategoryStatusResult( + $this->core->call( + 'crm.dealcategory.status', + [ + 'id' => $categoryId, + ] + ) + ); + } + + /** + * Updates an existing category. + * + * @link https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_update.php + * + * @param int $categoryId + * @param array{ + * ID?: int, + * CREATED_DATE?: string, + * NAME?: string, + * IS_LOCKED?: string, + * SORT?: int, + * } $fields + * + * @return UpdatedItemResult + * @throws BaseException + * @throws TransportException + */ + public function update(int $categoryId, array $fields): UpdatedItemResult + { + return new UpdatedItemResult( + $this->core->call( + 'crm.dealcategory.update', + [ + 'id' => $categoryId, + 'fields' => $fields, + ] + ) + ); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deals/Service/DealCategory.php b/src/Services/CRM/Deals/Service/DealCategory.php deleted file mode 100644 index ee1e407f..00000000 --- a/src/Services/CRM/Deals/Service/DealCategory.php +++ /dev/null @@ -1,245 +0,0 @@ -log->debug( - 'add.start', - [ - 'fields' => $fields, - ] - ); - - $result = $this->core->call( - 'crm.dealcategory.add', - [ - 'fields' => $fields, - ] - ); - - $this->log->debug('add.finish'); - - return $result; - } - - /** - * @param int $categoryId - * - * @return Response - * @throws BaseException - * @throws TransportException - */ - public function delete(int $categoryId): Response - { - $this->log->debug( - 'delete.start', - [ - 'categoryId' => $categoryId, - ] - ); - - $result = $this->core->call( - 'crm.dealcategory.delete', - [ - 'id' => $categoryId, - ] - ); - - $this->log->debug('delete.finish'); - - return $result; - } - - /** - * @return Response - * @throws BaseException - * @throws TransportException - */ - public function fields(): Response - { - $this->log->debug('fields.start'); - - $result = $this->core->call('crm.dealcategory.fields'); - - $this->log->debug('fields.finish'); - - return $result; - } - - /** - * @param int $categoryId - * - * @return Response - * @throws BaseException - * @throws TransportException - */ - public function get(int $categoryId): Response - { - $this->log->debug( - 'get.start', - [ - 'categoryId' => $categoryId, - ] - ); - - $result = $this->core->call( - 'crm.dealcategory.get', - [ - 'id' => $categoryId, - ] - ); - - $this->log->debug('get.finish'); - - return $result; - } - - /** - * @return Response - * @throws BaseException - * @throws TransportException - */ - public function getDefaultCategorySettings(): Response - { - $this->log->debug(' getDefaultCategorySettings.start'); - - $result = $this->core->call('crm.dealcategory.default.get'); - - $this->log->debug(' getDefaultCategorySettings.finish'); - - return $result; - } - - /** - * @return Response - * @throws BaseException - * @throws TransportException - */ - public function setDefaultCategoryName(string $name): Response - { - $this->log->debug('setDefaultCategoryName.start'); - - $result = $this->core->call( - 'crm.dealcategory.default.set', - [ - 'name' => $name, - ] - ); - - $this->log->debug('setDefaultCategoryName.finish'); - - return $result; - } - - /** - * @param array $order - * @param array $filter - * @param array $select - * @param int $start - * - * @return Response - * @throws BaseException - * @throws TransportException - */ - public function list(array $order, array $filter, array $select, int $start): Response - { - $this->log->debug( - 'list.start', - [ - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'start' => $start, - ] - ); - - $result = $this->core->call( - 'crm.dealcategory.list', - [ - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'start' => $start, - ] - ); - - $this->log->debug('list.finish'); - - return $result; - } - - /** - * @param int $categoryId - * - * @return Response - * @throws BaseException - * @throws TransportException - */ - public function getStatus(int $categoryId): Response - { - $this->log->debug( - 'getStatus.start', - [ - 'categoryId' => $categoryId, - ] - ); - - $result = $this->core->call( - 'crm.dealcategory.status', - [ - 'id' => $categoryId, - ] - ); - - $this->log->debug('getStatus.finish'); - - return $result; - } - - /** - * @param int $categoryId - * @param array $fields - * - * @return Response - * @throws BaseException - * @throws TransportException - */ - public function update(int $categoryId, array $fields): Response - { - $this->log->debug( - 'update.start', - [ - 'categoryId' => $categoryId, - 'fields' => $fields, - ] - ); - - $result = $this->core->call('crm.dealcategory.update'); - - $this->log->debug('update.finish'); - - return $result; - } -} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Deal/Service/DealCategoryTest.php b/tests/Integration/Services/CRM/Deal/Service/DealCategoryTest.php new file mode 100644 index 00000000..0507a601 --- /dev/null +++ b/tests/Integration/Services/CRM/Deal/Service/DealCategoryTest.php @@ -0,0 +1,163 @@ +dealCategory->list([], [], [], 0)->getCoreResponse()->getResponseData()->getPagination()->getTotal(); + $this::assertGreaterThanOrEqual( + 1, + $this->dealCategory->add( + [ + 'NAME' => 'test', + 'SORT' => 20, + ] + )->getId() + ); + $countAfter = $this->dealCategory->list([], [], [], 0)->getCoreResponse()->getResponseData()->getPagination()->getTotal(); + + $this::assertEquals($countBefore + 1, $countAfter); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\DealCategory::delete + * @throws BaseException + * @throws TransportException + */ + public function testDelete(): void + { + $this::assertTrue( + $this->dealCategory->delete( + $this->dealCategory->add( + [ + 'NAME' => 'test_name', + ] + )->getId() + )->isSuccess() + ); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\DealCategory::fields + * @throws BaseException + * @throws TransportException + */ + public function testFields(): void + { + $this::assertIsArray($this->dealCategory->fields()->getFieldsDescription()); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\DealCategory::getDefaultCategorySettings + * @throws BaseException + * @throws TransportException + */ + public function testDealCategoryDefaultGet(): void + { + $this::assertGreaterThanOrEqual(0, $this->dealCategory->getDefaultCategorySettings()->getDealCategoryFields()->ID); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\DealCategory::setDefaultCategorySettings + * @throws BaseException + * @throws TransportException + */ + public function testDealCategoryDefaultSet(): void + { + $oldName = $this->dealCategory->getDefaultCategorySettings()->getDealCategoryFields()->NAME; + $newName = (string)time(); + $this::assertTrue($this->dealCategory->setDefaultCategorySettings(['NAME' => $newName])->isSuccess()); + $this::assertNotSame($oldName, $this->dealCategory->getDefaultCategorySettings()->getDealCategoryFields()->NAME); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\DealCategory::get + * @throws BaseException + * @throws TransportException + */ + public function testDealCategoryGet(): void + { + $newCategory = [ + 'NAME' => 'test new deal category', + 'SORT' => 300, + ]; + + $newCategoryId = $this->dealCategory->add($newCategory)->getId(); + $category = $this->dealCategory->get($newCategoryId); + + $this::assertEquals($newCategory['NAME'], $category->getDealCategoryFields()->NAME); + $this::assertEquals($newCategory['SORT'], $category->getDealCategoryFields()->SORT); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\DealCategory::list + * + * @throws BaseException + * @throws TransportException + */ + public function testList(): void + { + $res = $this->dealCategory->list([], [], [], 0); + $this::assertGreaterThanOrEqual(1, count($res->getDealCategories())); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\DealCategory::getStatus + * @throws BaseException + * @throws TransportException + */ + public function testDealCategoryStatus(): void + { + $newCategory = [ + 'NAME' => 'test new deal category', + 'SORT' => 300, + ]; + $newCategoryId = $this->dealCategory->add($newCategory)->getId(); + $status = $this->dealCategory->getStatus($newCategoryId); + $this::assertGreaterThan(1, strlen($status->getDealCategoryTypeId())); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\DealCategory::update + * @throws BaseException + * @throws TransportException + */ + public function testUpdate(): void + { + $newCategory = [ + 'NAME' => 'test new deal category', + 'SORT' => 300, + ]; + $newCategoryId = $this->dealCategory->add($newCategory)->getId(); + $this::assertTrue($this->dealCategory->update($newCategoryId, ['NAME' => 'updated'])->isSuccess()); + $this::assertEquals('updated', $this->dealCategory->get($newCategoryId)->getDealCategoryFields()->NAME); + } + + public function setUp(): void + { + $this->dealCategory = Fabric::getServiceBuilder()->getCRMScope()->dealCategory(); + } +} \ No newline at end of file From e56b0a981ccf0d9025a18622ab305ecda0cd5826 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 31 Jan 2021 00:51:13 +0300 Subject: [PATCH 209/647] add phpstan github action --- .github/workflows/phpstan.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/workflows/phpstan.yml diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml new file mode 100644 index 00000000..c1393171 --- /dev/null +++ b/.github/workflows/phpstan.yml @@ -0,0 +1,18 @@ +on: + push: + pull_request: + +name: PHPStan checks + +jobs: + phpstan: + name: PHPStan + + runs-on: ubuntu-latest + + steps: + - name: "Checkout" + uses: actions/checkout@v2 + + - name: PHPStan + uses: docker://oskarstark/phpstan-ga \ No newline at end of file From 4a452724684a4ebd4437aecfaecb8ec23800f31c Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 31 Jan 2021 00:55:28 +0300 Subject: [PATCH 210/647] add phpstan github action --- phpstan.neon => phpstan.neon.dist | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename phpstan.neon => phpstan.neon.dist (100%) diff --git a/phpstan.neon b/phpstan.neon.dist similarity index 100% rename from phpstan.neon rename to phpstan.neon.dist From 03e2d97738b3285a6da0aa9a10eacad2cb9d3dc7 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 31 Jan 2021 00:57:36 +0300 Subject: [PATCH 211/647] add phpstan github action 2 --- .github/workflows/phpstan.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index c1393171..1869b179 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -15,4 +15,6 @@ jobs: uses: actions/checkout@v2 - name: PHPStan - uses: docker://oskarstark/phpstan-ga \ No newline at end of file + uses: docker://oskarstark/phpstan-ga + with: + args: analyse \ No newline at end of file From 0606eab685c9adbb975eb57d6eff320e0709e5bc Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 31 Jan 2021 01:01:26 +0300 Subject: [PATCH 212/647] fix github actions --- .github/workflows/{ci.yml => phpunit.yml} | 2 +- phpstan.neon.dist | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename .github/workflows/{ci.yml => phpunit.yml} (96%) diff --git a/.github/workflows/ci.yml b/.github/workflows/phpunit.yml similarity index 96% rename from .github/workflows/ci.yml rename to .github/workflows/phpunit.yml index 147f70c1..b52fa47f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/phpunit.yml @@ -1,4 +1,4 @@ -name: "Continuous Integration" +name: "PHPUnit tests" on: - push diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 7aef7b70..30f5fdf5 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,5 +1,5 @@ parameters: - level: 5 + level: 4 paths: - src/ - tests/ From 1fe5ae56444adf54383802c1e2cfb7b7424507d2 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 31 Jan 2021 01:38:55 +0300 Subject: [PATCH 213/647] add unit tests for service builders --- .../Services/CRM/CRMServiceBuilderTest.php | 90 +++++++++++++++++++ tests/Unit/Services/ServiceBuilderTest.php | 53 +++++++++++ tests/Unit/Stubs/NullBatch.php | 11 +++ 3 files changed, 154 insertions(+) create mode 100644 tests/Unit/Services/CRM/CRMServiceBuilderTest.php create mode 100644 tests/Unit/Services/ServiceBuilderTest.php diff --git a/tests/Unit/Services/CRM/CRMServiceBuilderTest.php b/tests/Unit/Services/CRM/CRMServiceBuilderTest.php new file mode 100644 index 00000000..7084603e --- /dev/null +++ b/tests/Unit/Services/CRM/CRMServiceBuilderTest.php @@ -0,0 +1,90 @@ +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 + { + $this->serviceBuilder = (new ServiceBuilder(new NullCore(), new NullBatch(), new NullLogger()))->getCRMScope(); + } +} \ No newline at end of file diff --git a/tests/Unit/Services/ServiceBuilderTest.php b/tests/Unit/Services/ServiceBuilderTest.php new file mode 100644 index 00000000..2bc8b03d --- /dev/null +++ b/tests/Unit/Services/ServiceBuilderTest.php @@ -0,0 +1,53 @@ +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 + { + $this->serviceBuilder = new ServiceBuilder(new NullCore(), new NullBatch(), new NullLogger()); + } +} \ No newline at end of file diff --git a/tests/Unit/Stubs/NullBatch.php b/tests/Unit/Stubs/NullBatch.php index 5ffdb8ef..d6286ed8 100644 --- a/tests/Unit/Stubs/NullBatch.php +++ b/tests/Unit/Stubs/NullBatch.php @@ -27,4 +27,15 @@ public function getTraversableList(string $apiMethod, array $order, array $filte { yield []; } + + /** + * @param string $apiMethod + * @param array $entityItems + * + * @return Generator + */ + public function addEntityItems(string $apiMethod, array $entityItems): Generator + { + yield []; + } } \ No newline at end of file From 988eafbfaef148bf4ad2e538994b45878241b8c2 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 31 Jan 2021 01:40:56 +0300 Subject: [PATCH 214/647] add unit tests for service builders --- phpstan.neon.dist | 2 +- src/Services/CRM/CRMServiceBuilder.php | 20 ++++---------------- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 30f5fdf5..31d2ac83 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,5 +1,5 @@ parameters: - level: 4 + level: 1 paths: - src/ - tests/ diff --git a/src/Services/CRM/CRMServiceBuilder.php b/src/Services/CRM/CRMServiceBuilder.php index 36a13798..f55bde80 100644 --- a/src/Services/CRM/CRMServiceBuilder.php +++ b/src/Services/CRM/CRMServiceBuilder.php @@ -70,18 +70,6 @@ public function deal(): Deal\Service\Deal return $this->serviceCache[__METHOD__]; } - /** - * @return Deal\Service\Products - */ - public function products(): Deal\Service\Products - { - if (!isset($this->serviceCache[__METHOD__])) { - $this->serviceCache[__METHOD__] = new Deal\Service\Products($this->core, $this->log); - } - - return $this->serviceCache[__METHOD__]; - } - /** * @return Contact\Service\Contact */ @@ -104,19 +92,19 @@ public function contact(): Contact\Service\Contact public function dealProductRows(): Deal\Service\DealProductRows { if (!isset($this->serviceCache[__METHOD__])) { - $this->serviceCache[__METHOD__] = new Deal\Service\DealProductRows($this->core, $this->batch, $this->log); + $this->serviceCache[__METHOD__] = new Deal\Service\DealProductRows($this->core, $this->log); } return $this->serviceCache[__METHOD__]; } /** - * @return Deal\Service\DealCategoryStages + * @return Deal\Service\DealCategoryStage */ - public function dealCategoryStages(): Deal\Service\DealCategoryStages + public function dealCategoryStage(): Deal\Service\DealCategoryStage { if (!isset($this->serviceCache[__METHOD__])) { - $this->serviceCache[__METHOD__] = new Deal\Service\DealCategoryStages($this->core, $this->batch, $this->log); + $this->serviceCache[__METHOD__] = new Deal\Service\DealCategoryStage($this->core, $this->log); } return $this->serviceCache[__METHOD__]; From a36966441a1edcb95cbab6878b61145048be0585 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 31 Jan 2021 01:49:24 +0300 Subject: [PATCH 215/647] add unit tests for service builders --- src/Services/Main/MainServiceBuilder.php | 2 +- .../Services/Main/MainServiceBuilderTest.php | 37 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 tests/Unit/Services/Main/MainServiceBuilderTest.php diff --git a/src/Services/Main/MainServiceBuilder.php b/src/Services/Main/MainServiceBuilder.php index db4033e5..9591f032 100644 --- a/src/Services/Main/MainServiceBuilder.php +++ b/src/Services/Main/MainServiceBuilder.php @@ -20,7 +20,7 @@ class MainServiceBuilder extends AbstractServiceBuilder public function main(): Main { if (!isset($this->serviceCache[__METHOD__])) { - $this->serviceCache[__METHOD__] = new Main($this->core, $this->batch, $this->log); + $this->serviceCache[__METHOD__] = new Main($this->core, $this->log); } return $this->serviceCache[__METHOD__]; diff --git a/tests/Unit/Services/Main/MainServiceBuilderTest.php b/tests/Unit/Services/Main/MainServiceBuilderTest.php new file mode 100644 index 00000000..710084b2 --- /dev/null +++ b/tests/Unit/Services/Main/MainServiceBuilderTest.php @@ -0,0 +1,37 @@ +serviceBuilder->main(); + $this::assertTrue(true); + } + + + public function setUp(): void + { + $this->serviceBuilder = (new ServiceBuilder(new NullCore(), new NullBatch(), new NullLogger()))->getMainScope(); + } +} \ No newline at end of file From 2747fe8a29ed71fe56cdf87ad7f2771dc679054d Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 31 Jan 2021 01:52:42 +0300 Subject: [PATCH 216/647] add unit tests for service builders --- src/Services/IM/IMServiceBuilder.php | 2 +- .../Unit/Services/IM/IMServiceBuilderTest.php | 37 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 tests/Unit/Services/IM/IMServiceBuilderTest.php diff --git a/src/Services/IM/IMServiceBuilder.php b/src/Services/IM/IMServiceBuilder.php index 890c93a1..839ec8ed 100644 --- a/src/Services/IM/IMServiceBuilder.php +++ b/src/Services/IM/IMServiceBuilder.php @@ -20,7 +20,7 @@ class IMServiceBuilder extends AbstractServiceBuilder public function IM(): IM { if (!isset($this->serviceCache[__METHOD__])) { - $this->serviceCache[__METHOD__] = new IM($this->core, $this->batch, $this->log); + $this->serviceCache[__METHOD__] = new IM($this->core, $this->log); } return $this->serviceCache[__METHOD__]; diff --git a/tests/Unit/Services/IM/IMServiceBuilderTest.php b/tests/Unit/Services/IM/IMServiceBuilderTest.php new file mode 100644 index 00000000..37384826 --- /dev/null +++ b/tests/Unit/Services/IM/IMServiceBuilderTest.php @@ -0,0 +1,37 @@ +serviceBuilder->IM(); + $this::assertTrue(true); + } + + + public function setUp(): void + { + $this->serviceBuilder = (new ServiceBuilder(new NullCore(), new NullBatch(), new NullLogger()))->getIMScope(); + } +} \ No newline at end of file From 08d7fb2162eb8497320f19112a7036e8d10f1edc Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 31 Jan 2021 18:11:38 +0300 Subject: [PATCH 217/647] add deal category stages --- CHANGELOG.md | 91 ++++++++++++++----- .../Result/DealCategoryStageItemResult.php | 18 ++++ .../Deal/Result/DealCategoryStagesResult.php | 32 +++++++ .../CRM/Deal/Service/DealCategoryStage.php | 37 ++++++++ .../CRM/Deals/Service/DealCategoryStages.php | 35 ------- .../Deal/Service/DealCategoryStageTest.php | 45 +++++++++ 6 files changed, 201 insertions(+), 57 deletions(-) create mode 100644 src/Services/CRM/Deal/Result/DealCategoryStageItemResult.php create mode 100644 src/Services/CRM/Deal/Result/DealCategoryStagesResult.php create mode 100644 src/Services/CRM/Deal/Service/DealCategoryStage.php delete mode 100644 src/Services/CRM/Deals/Service/DealCategoryStages.php create mode 100644 tests/Integration/Services/CRM/Deal/Service/DealCategoryStageTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 700963d6..351f291a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,19 +1,37 @@ # bitrix24-php-sdk change log -## 2.0 DEV -* remove all old code + +## 2.0-alpha.2 (31.01.2021) + +* remove Travis CI and migrate to Github Actions +* add unit-tests +* add phpstan checks in independent github action +* add in scope «CRM» Contacts service and integration test +* add in scope «CRM» Contacts batch service and integration test +* add in scope «CRM» Products service and integration test +* add in scope «CRM» Settings service and integration test +* add in scope «CRM» DealCategoryStage service and integration test +* add in scope «IM» IM service and integration test +* add in default scope «Main» default service + +## 2.0-alpha.1 (11.07.2020) + +* remove all v1 code * migrate to Symfony HttpClient * add documentation webhook auth type * add OAuth 2.0 support * add Events support ## 0.7.0 (11.07.2020) + * add arguments in method `Bitrix24\Bizproc\Robot::add` for return results support ## 0.6.2 (12.09.2019) + * remove in method, `processBatchCalls` remove call `handleBitrix24APILevelErrors` * remove php 5.x branch in travis config ## 0.6.1 (20.03.2019) + * add `offset` parameter to entity `CRM\Status\Status` in method `getList` * add `offset` parameter to entity `User\User` in method `getList` * add method `messageAdd` to entity `Bitrix24\Bitrix24` @@ -26,8 +44,9 @@ * fix log level in method `Bitrix24::handleBitrix24APILevelErrors` ## 0.6.0 (18.02.2018) + * add support for `FaceTracker` entity -* add presets for request timing information +* add presets for request timing information * add all methods for sonetgroup * add method `crm.contact.userfield.update` * add activities methods @@ -44,6 +63,7 @@ * add new placement presets for detail page ## 0.5.4 (8.07.2017) + * add Callback for expired token. Fix pullrequest#63 by valga * add method `update` in class `Bitrix24\CRM\Product` * increased curl time out @@ -51,32 +71,43 @@ * add batch calls method to bitrix24 api client interface ## 0.5.3 (20.05.2017) + * add class `Bitrix24\Placement\Placement` * add preset `Bitrix24\Presets\Placement\Placement` with placement codes * add preset `Bitrix24\Presets\Placement\Fields` with placement fields ## 0.5.2 (11.05.2017) + * add preset `Bitrix24\Presets\CRM\Product\ProductRowFields` * updated preset `Bitrix24\Presets\CRM\Contact\Fields` * updated preset `Bitrix24\Presets\CRM\Deal\Fields` * updated preset `Bitrix24\Presets\CRM\Lead\Fields` ## 0.5.1 (30.04.2017) + * add preset `Bitrix24\Presets\CRM\Product\Fields` * add method `add` in class `Bitrix24\CRM\Product` ## 0.5.0 (4.09.2016) + * add class `Bitrix24\CRM\Quote` see pr [Added support for Quote API calls](https://github.com/mesilov/bitrix24-php-sdk/pull/53/) -* add support http status 301 moved permanently in class `Bitrix24` see issue [301 Moved Permanently #49](https://github.com/mesilov/bitrix24-php-sdk/issues/49) +* add support http status 301 moved permanently in class `Bitrix24` see + issue [301 Moved Permanently #49](https://github.com/mesilov/bitrix24-php-sdk/issues/49) * fixed bug in class `Bitrix24` see pr [Issue in the isAccessTokenExpire method](https://github.com/mesilov/bitrix24-php-sdk/pull/54) ## 0.4.1 (4.08.2016) -* add new events in class `Bitrix24\Presets\Event\Event` see issue [Add new bitrix24 events #44](https://github.com/mesilov/bitrix24-php-sdk/issues/44) -* add new scope in class `Bitrix24\Presets\Scope` see issue [Update scope presets class #47](https://github.com/mesilov/bitrix24-php-sdk/issues/47) -* remove file with old deprecated exceptions see issue [Move all exceptions in namespace «Exceptions» #46](https://github.com/mesilov/bitrix24-php-sdk/issues/46) + +* add new events in class `Bitrix24\Presets\Event\Event` see + issue [Add new bitrix24 events #44](https://github.com/mesilov/bitrix24-php-sdk/issues/44) +* add new scope in class `Bitrix24\Presets\Scope` see + issue [Update scope presets class #47](https://github.com/mesilov/bitrix24-php-sdk/issues/47) +* remove file with old deprecated exceptions see + issue [Move all exceptions in namespace «Exceptions» #46](https://github.com/mesilov/bitrix24-php-sdk/issues/46) ## 0.4.0 (16.07.2016) -* remove all exceptions in namespace `\Exceptions` see issue [Move all exceptions in namespace «Exceptions» #46](https://github.com/mesilov/bitrix24-php-sdk/issues/46) + +* remove all exceptions in namespace `\Exceptions` see + issue [Move all exceptions in namespace «Exceptions» #46](https://github.com/mesilov/bitrix24-php-sdk/issues/46) * add class `Bitrix24\Exceptions\Bitrix24Exception` * add class `Bitrix24\Exceptions\Bitrix24IoException` * add class `Bitrix24\Exceptions\Bitrix24EmptyResponseException` @@ -100,37 +131,48 @@ * updated class `Bitrix24\Bitrix24SecurityException` mark as **deprecated** ## 0.3.4 (06.06.2016) + * add exception class `Bitrix24EmptyResponseException` * in class `Bitrix24` add debug information for some error types -* temporary remove calls to oauth.bitrix.info for methods `app.info` and `app.stat` see issue [Fix errors after change REST API to support self hosted version #43](https://github.com/mesilov/bitrix24-php-sdk/issues/43) +* temporary remove calls to oauth.bitrix.info for methods `app.info` and `app.stat` see + issue [Fix errors after change REST API to support self hosted version #43](https://github.com/mesilov/bitrix24-php-sdk/issues/43) ## 0.3.3 (28.05.2016) -* fixed bug in class `Bitrix24` see issue [Fix errors after change REST API to support self hosted version #43](https://github.com/mesilov/bitrix24-php-sdk/issues/43) + +* fixed bug in class `Bitrix24` see + issue [Fix errors after change REST API to support self hosted version #43](https://github.com/mesilov/bitrix24-php-sdk/issues/43) ## 0.3.2 (07.05.2016) -* fixed bug in class `Bitrix24\Im\Notify` see issue [ATTACH_ERROR for calls method im.notify for empty attach #42](https://github.com/mesilov/bitrix24-php-sdk/issues/42) - + +* fixed bug in class `Bitrix24\Im\Notify` see + issue [ATTACH_ERROR for calls method im.notify for empty attach #42](https://github.com/mesilov/bitrix24-php-sdk/issues/42) + ## 0.3.1 (04.05.2016) + * add `dev` branch in GitHub repo * fixed bug in class `Bitrix24\Im\Attach\Attach`, method `Attach::getAttachItems()` already return array ## 0.3.0 (04.05.2016) + * add class `Bitrix24\Im\Attach\Item\Message` class implements work with string messages in attach item -* add interface `Bitrix24\Presets\Im\iChatColor` with chat color presets +* add interface `Bitrix24\Presets\Im\iChatColor` with chat color presets * add phpUnit tests for items: - * `Bitrix24\Im\Attach\Item\Delimiter` - * `Bitrix24\Im\Attach\Item\File` - * `Bitrix24\Im\Attach\Item\Grid` - * `Bitrix24\Im\Attach\Item\Image` - * `Bitrix24\Im\Attach\Item\Link` - * `Bitrix24\Im\Attach\Item\Message` - * `Bitrix24\Im\Attach\Item\User` -* fixed bug in class `Bitrix24\Im\Attach\Attach` + * `Bitrix24\Im\Attach\Item\Delimiter` + * `Bitrix24\Im\Attach\Item\File` + * `Bitrix24\Im\Attach\Item\Grid` + * `Bitrix24\Im\Attach\Item\Image` + * `Bitrix24\Im\Attach\Item\Link` + * `Bitrix24\Im\Attach\Item\Message` + * `Bitrix24\Im\Attach\Item\User` +* fixed bug in class `Bitrix24\Im\Attach\Attach` ## 0.2.1 (27.04.2016) -* add exception class `Bitrix24PortalDeleted` and handle Bitrix24 portal deleted event. See issue [Add support for deleted portals #40](https://github.com/mesilov/bitrix24-php-sdk/issues/40) + +* add exception class `Bitrix24PortalDeleted` and handle Bitrix24 portal deleted event. See + issue [Add support for deleted portals #40](https://github.com/mesilov/bitrix24-php-sdk/issues/40) ## 0.2.0 (24.06.2015) + * add class `Deal` * add class `LiveFeedMessage` * add task fields presets @@ -149,6 +191,7 @@ * remove class `Bitrix24\Task\TaskItem` ## 0.1.4 (18.04.2015) + * add presets for user fields data type structure * add method `Update` and predefined constants in class `Invoice` * add protected method `handleBitrix24APILevelErrors` in a base class @@ -163,6 +206,7 @@ * fixed bug in Fix method isAccessTokenExpire ## 0.1.3 (24.08.2014) + * add const `TOTAL` and `RESULT` for class `Bitrix24\Presets\Main` * add class `Bitrix24\Presets\Users\Fields` for Bitrix24 users fields * add class `Bitrix24\Departments\Department` @@ -178,6 +222,7 @@ * fixed bug in __construct in abstract class `Bitrix24Entity` ## 0.1.2 (22.01.2014) + * add security sign support in api-call * add class `User` * add method «admin» — Check is current user admin @@ -186,9 +231,11 @@ * add MIT-LICENSE ## 0.1.1 (9.10.2013) + * add namespace support * add classes of Bitrix24 parts: tasks, sonet * add base class `Bitrix24Entity` ## 0.1.0 (26.10.2013) + * Initial release \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealCategoryStageItemResult.php b/src/Services/CRM/Deal/Result/DealCategoryStageItemResult.php new file mode 100644 index 00000000..50ca80ff --- /dev/null +++ b/src/Services/CRM/Deal/Result/DealCategoryStageItemResult.php @@ -0,0 +1,18 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData() as $deal) { + $res[] = new DealCategoryStageItemResult($deal); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Service/DealCategoryStage.php b/src/Services/CRM/Deal/Service/DealCategoryStage.php new file mode 100644 index 00000000..5eb05e5d --- /dev/null +++ b/src/Services/CRM/Deal/Service/DealCategoryStage.php @@ -0,0 +1,37 @@ +core->call( + 'crm.dealcategory.stage.list', + [ + 'id' => $categoryId, + ] + ) + ); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deals/Service/DealCategoryStages.php b/src/Services/CRM/Deals/Service/DealCategoryStages.php deleted file mode 100644 index 789d93cf..00000000 --- a/src/Services/CRM/Deals/Service/DealCategoryStages.php +++ /dev/null @@ -1,35 +0,0 @@ -core->call( - 'crm.dealcategory.stage.list', - [ - 'id' => $categoryId, - ] - ); - } -} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Deal/Service/DealCategoryStageTest.php b/tests/Integration/Services/CRM/Deal/Service/DealCategoryStageTest.php new file mode 100644 index 00000000..1d2066d3 --- /dev/null +++ b/tests/Integration/Services/CRM/Deal/Service/DealCategoryStageTest.php @@ -0,0 +1,45 @@ +dealCategory->add(['NAME' => 'php unit test'])->getId(); + $res = $this->dealCategoryStage->list($newCategoryId); + $this::assertGreaterThan(1, count($res->getDealCategoryStages())); + } + + /** + * @throws InvalidArgumentException + */ + public function setUp(): void + { + $this->dealCategoryStage = Fabric::getServiceBuilder()->getCRMScope()->dealCategoryStage(); + $this->dealCategory = Fabric::getServiceBuilder()->getCRMScope()->dealCategory(); + } +} \ No newline at end of file From 784fd7af8783d918fbf9d3b91aa80974293ef36f Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 1 Feb 2021 00:05:41 +0300 Subject: [PATCH 218/647] add deal product rows --- CHANGELOG.md | 1 + .../CRM/Deal/Service/DealProductRows.php | 79 +++++++++++++++++++ .../CRM/Deals/Service/DealProductRows.php | 79 ------------------- .../CRM/Deal/Service/DealProductRowsTest.php | 73 +++++++++++++++++ 4 files changed, 153 insertions(+), 79 deletions(-) create mode 100644 src/Services/CRM/Deal/Service/DealProductRows.php delete mode 100644 src/Services/CRM/Deals/Service/DealProductRows.php create mode 100644 tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 351f291a..9e19c005 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ * add in scope «CRM» Products service and integration test * add in scope «CRM» Settings service and integration test * add in scope «CRM» DealCategoryStage service and integration test +* add in scope «CRM» DealProductRows service and integration test * add in scope «IM» IM service and integration test * add in default scope «Main» default service diff --git a/src/Services/CRM/Deal/Service/DealProductRows.php b/src/Services/CRM/Deal/Service/DealProductRows.php new file mode 100644 index 00000000..1c1a6627 --- /dev/null +++ b/src/Services/CRM/Deal/Service/DealProductRows.php @@ -0,0 +1,79 @@ +core->call( + 'crm.deal.productrows.get', + [ + 'id' => $dealId, + ] + ) + ); + } + + /** + * @param int $dealId + * @param array $productRows + * + * @return UpdatedItemResult + * @throws BaseException + * @throws TransportException + */ + public function set(int $dealId, array $productRows): UpdatedItemResult + { + return new UpdatedItemResult( + $this->core->call( + 'crm.deal.productrows.set', + [ + 'id' => $dealId, + 'rows' => $productRows, + ] + ) + ); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deals/Service/DealProductRows.php b/src/Services/CRM/Deals/Service/DealProductRows.php deleted file mode 100644 index ef49b191..00000000 --- a/src/Services/CRM/Deals/Service/DealProductRows.php +++ /dev/null @@ -1,79 +0,0 @@ -log->debug( - 'get.start', - [ - 'dealId' => $dealId, - ] - ); - - $result = $this->core->call( - 'crm.deal.productrows.get', - [ - 'id' => $dealId, - ] - ); - - $this->log->debug('get.finish'); - - return $result; - } - - /** - * @param int $dealId - * @param array $productRows - * - * @return Response - * @throws BaseException - * @throws TransportException - */ - public function set(int $dealId, array $productRows): Response - { - $this->log->debug( - 'set.start', - [ - 'dealId' => $dealId, - 'productRows' => $productRows, - ] - ); - - - $result = $this->core->call( - 'crm.deal.productrows.set', - [ - 'id' => $dealId, - 'rows' => $productRows, - ] - ); - - - $this->log->debug('set.finish'); - - return $result; - } -} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php b/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php new file mode 100644 index 00000000..0b45ad41 --- /dev/null +++ b/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php @@ -0,0 +1,73 @@ +dealService->add(['TITLE' => 'test deal'])->getId(); + $this::assertCount(0, $this->dealProductRowsService->get($newDealId)->getProductRows()); + $this::assertTrue( + $this->dealProductRowsService->set( + $newDealId, + [ + [ + 'PRODUCT_NAME' => 'qqqq', + ], + ] + )->isSuccess() + ); + $this::assertCount(1, $this->dealProductRowsService->get($newDealId)->getProductRows()); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\DealProductRows::get + */ + public function testGet(): void + { + $newDealId = $this->dealService->add(['TITLE' => 'test deal'])->getId(); + $this::assertCount(0, $this->dealProductRowsService->get($newDealId)->getProductRows()); + $this::assertTrue( + $this->dealProductRowsService->set( + $newDealId, + [ + [ + 'PRODUCT_NAME' => 'qqqq', + ], + ] + )->isSuccess() + ); + $this::assertCount(1, $this->dealProductRowsService->get($newDealId)->getProductRows()); + } + + public function setUp(): void + { + $this->dealService = Fabric::getServiceBuilder()->getCRMScope()->deal(); + $this->dealProductRowsService = Fabric::getServiceBuilder()->getCRMScope()->dealProductRows(); + } +} \ No newline at end of file From 73703f754b2711eb8765ed32459c5e08ab3a3cd9 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 1 Feb 2021 00:18:24 +0300 Subject: [PATCH 219/647] add deal product rows fix --- composer.json | 3 +++ src/Services/CRM/Deal/Service/DealProductRows.php | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/composer.json b/composer.json index f2360d1a..58212036 100644 --- a/composer.json +++ b/composer.json @@ -50,6 +50,9 @@ "scripts": { "unit-tests": [ "phpunit --colors=always --verbose" + ], + "phpstan-analyse": [ + "vendor/bin/phpstan analyse" ] } } \ No newline at end of file diff --git a/src/Services/CRM/Deal/Service/DealProductRows.php b/src/Services/CRM/Deal/Service/DealProductRows.php index 1c1a6627..3704bd20 100644 --- a/src/Services/CRM/Deal/Service/DealProductRows.php +++ b/src/Services/CRM/Deal/Service/DealProductRows.php @@ -18,6 +18,10 @@ class DealProductRows extends AbstractService { /** + * Returns products inside the specified deal. + * + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_productrows_get.php + * * @param int $dealId * * @return DealProductRowItemsResult @@ -37,6 +41,10 @@ public function get(int $dealId): DealProductRowItemsResult } /** + * Creates or updates product entries inside the specified deal. + * + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_productrows_set.php + * * @param int $dealId * @param array Date: Mon, 1 Feb 2021 00:48:24 +0300 Subject: [PATCH 220/647] add deal product rows result --- .../Deal/Result/DealProductRowItemResult.php | 34 +++++++++++++++++++ .../Deal/Result/DealProductRowItemsResult.php | 31 +++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 src/Services/CRM/Deal/Result/DealProductRowItemResult.php create mode 100644 src/Services/CRM/Deal/Result/DealProductRowItemsResult.php diff --git a/src/Services/CRM/Deal/Result/DealProductRowItemResult.php b/src/Services/CRM/Deal/Result/DealProductRowItemResult.php new file mode 100644 index 00000000..5632778b --- /dev/null +++ b/src/Services/CRM/Deal/Result/DealProductRowItemResult.php @@ -0,0 +1,34 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData() as $productRow) { + $res[] = new DealProductRowItemResult($productRow); + } + + return $res; + } +} \ No newline at end of file From c0a53da1267eb7185797a8422d5a28f76996c254 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 1 Feb 2021 01:33:18 +0300 Subject: [PATCH 221/647] add deal contact service and test --- .github/workflows/phpunit.yml | 4 +- CHANGELOG.md | 3 +- .../Deal/Result/DealContactItemsResult.php | 30 +++ src/Services/CRM/Deal/Service/DealContact.php | 168 ++++++++++++++++ .../CRM/Deal/Service/DealContactTest.php | 189 ++++++++++++++++++ 5 files changed, 391 insertions(+), 3 deletions(-) create mode 100644 src/Services/CRM/Deal/Result/DealContactItemsResult.php create mode 100644 src/Services/CRM/Deal/Service/DealContact.php create mode 100644 tests/Integration/Services/CRM/Deal/Service/DealContactTest.php diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index b52fa47f..c0040183 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -9,7 +9,7 @@ env: jobs: tests: - name: "CI" + name: "PHPUnit tests" runs-on: ubuntu-latest @@ -17,7 +17,7 @@ jobs: matrix: php-version: - "7.4" - dependencies: [highest] + dependencies: [ highest ] steps: - name: "Checkout" diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e19c005..7a2da028 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ## 2.0-alpha.2 (31.01.2021) * remove Travis CI and migrate to Github Actions -* add unit-tests +* add unit-tests in independent github action * add phpstan checks in independent github action * add in scope «CRM» Contacts service and integration test * add in scope «CRM» Contacts batch service and integration test @@ -11,6 +11,7 @@ * add in scope «CRM» Settings service and integration test * add in scope «CRM» DealCategoryStage service and integration test * add in scope «CRM» DealProductRows service and integration test +* add in scope «CRM» DealContact service and integration test * add in scope «IM» IM service and integration test * add in default scope «Main» default service diff --git a/src/Services/CRM/Deal/Result/DealContactItemsResult.php b/src/Services/CRM/Deal/Result/DealContactItemsResult.php new file mode 100644 index 00000000..b0f639d8 --- /dev/null +++ b/src/Services/CRM/Deal/Result/DealContactItemsResult.php @@ -0,0 +1,30 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData() as $dealContact) { + $res[] = new DealContactItemResult($dealContact); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Service/DealContact.php b/src/Services/CRM/Deal/Service/DealContact.php new file mode 100644 index 00000000..c5c8a0f5 --- /dev/null +++ b/src/Services/CRM/Deal/Service/DealContact.php @@ -0,0 +1,168 @@ +core->call( + 'crm.deal.contact.add', + [ + 'id' => $dealId, + 'fields' => [ + 'CONTACT_ID' => $contactId, + 'IS_PRIMARY' => $isPrimary, + 'SORT' => $sort, + ], + ] + ) + ); + } + + /** + * Returns field descriptions for the deal-contact link used by methods of family crm.deal.contact.* + * + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_contact_fields.php + * @return FieldsResult + * @throws BaseException + * @throws TransportException + */ + public function fields(): FieldsResult + { + return new FieldsResult($this->core->call('crm.deal.contact.fields')); + } + + /** + * Returns a set of contacts, associated with the specified deal. + * + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_contact_items_get.php + * + * @param int $dealId + * + * @return DealContactItemsResult + * @throws BaseException + * @throws TransportException + */ + public function itemsGet(int $dealId): DealContactItemsResult + { + return new DealContactItemsResult( + $this->core->call( + 'crm.deal.contact.items.get', + [ + 'id' => $dealId, + ] + ) + ); + } + + /** + * Clears a set of contacts, associated with the specified deal. + * + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_contact_items_delete.php + * + * @param int $dealId + * + * @return DeletedItemResult + * @throws BaseException + * @throws TransportException + */ + public function itemsDelete(int $dealId): DeletedItemResult + { + return new DeletedItemResult( + $this->core->call( + 'crm.deal.contact.items.delete', + [ + 'id' => $dealId, + ] + ) + ); + } + + /** + * Set a set of contacts, associated with the specified seal. + * + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_contact_items_set.php + * + * @param int $dealId + * @param array $contactItems + * + * @return UpdatedItemResult + * @throws BaseException + * @throws TransportException + */ + public function itemsSet(int $dealId, array $contactItems): UpdatedItemResult + { + return new UpdatedItemResult( + $this->core->call( + 'crm.deal.contact.items.set', + [ + 'id' => $dealId, + 'items' => $contactItems, + ] + ) + ); + } + + /** + * Deletes contact from a specified deal + * + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_contact_delete.php + * + * @param int $dealId + * @param int $contactId + * + * @return DeletedItemResult + * @throws BaseException + * @throws TransportException + */ + public function delete(int $dealId, int $contactId): DeletedItemResult + { + return new DeletedItemResult( + $this->core->call( + 'crm.deal.contact.delete', + [ + 'id' => $dealId, + 'fields' => [ + 'CONTACT_ID' => $contactId, + ], + ] + ) + ); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Deal/Service/DealContactTest.php b/tests/Integration/Services/CRM/Deal/Service/DealContactTest.php new file mode 100644 index 00000000..8666e0ee --- /dev/null +++ b/tests/Integration/Services/CRM/Deal/Service/DealContactTest.php @@ -0,0 +1,189 @@ +dealService->add(['TITLE' => 'test deal'])->getId(); + $this::assertGreaterThanOrEqual( + 1, + $this->dealContactService->add( + $dealId, + $this->contactService->add(['NAME' => 'test contact'], [])->getId(), + true + )->getId() + ); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\DealContact::add + * @throws BaseException + * @throws TransportException + */ + public function testAddWithSecondary(): void + { + $dealId = $this->dealService->add(['TITLE' => 'test deal'])->getId(); + + $this::assertGreaterThanOrEqual( + 1, + $this->dealContactService->add($dealId, $this->contactService->add(['NAME' => 'test contact 1'], [])->getId(), true)->getId() + ); + $this::assertGreaterThanOrEqual( + 1, + $this->dealContactService->add($dealId, $this->contactService->add(['NAME' => 'test contact 2'], [])->getId(), false)->getId() + ); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\DealContact::itemsGet + * @throws BaseException + * @throws TransportException + */ + public function testItemsGet(): void + { + $dealId = $this->dealService->add(['TITLE' => 'test deal'])->getId(); + $this::assertGreaterThanOrEqual( + 1, + $this->dealContactService->add( + $dealId, + $this->contactService->add(['NAME' => 'test contact 1'], [])->getId(), + true + )->getId() + ); + $this::assertGreaterThanOrEqual( + 1, + $this->dealContactService->add( + $dealId, + $this->contactService->add(['NAME' => 'test contact 2'], [])->getId(), + false + )->getId() + ); + + $this::assertCount(2, $this->dealContactService->itemsGet($dealId)->getDealContacts()); + } + + + /** + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\DealContact::itemsDelete + * @throws BaseException + * @throws TransportException + */ + public function testItemsDelete(): void + { + $dealId = $this->dealService->add(['TITLE' => 'test deal'])->getId(); + $this::assertGreaterThanOrEqual( + 1, + $this->dealContactService->add( + $dealId, + $this->contactService->add(['NAME' => 'test contact 1'], [])->getId(), + true + )->getId() + ); + $this::assertGreaterThanOrEqual( + 1, + $this->dealContactService->add( + $dealId, + $this->contactService->add(['NAME' => 'test contact 2'], [])->getId(), + false + )->getId() + ); + $this::assertCount(2, $this->dealContactService->itemsGet($dealId)->getDealContacts()); + $this::assertTrue($this->dealContactService->itemsDelete($dealId)->isSuccess()); + $this::assertCount(0, $this->dealContactService->itemsGet($dealId)->getDealContacts()); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\DealContact::itemsSet + * @throws BaseException + * @throws TransportException + */ + public function testItemsSet(): void + { + $dealId = $this->dealService->add(['TITLE' => 'test deal'])->getId(); + $contact1Id = $this->contactService->add(['NAME' => 'test contact 1'], [])->getId(); + $contact2Id = $this->contactService->add(['NAME' => 'test contact 2'], [])->getId(); + + $sort = 400; + + $this::assertTrue( + $this->dealContactService->itemsSet( + $dealId, + [ + [ + 'CONTACT_ID' => $contact2Id, + 'SORT' => $sort, + 'IS_PRIMARY' => 'Y', + ], + [ + 'CONTACT_ID' => $contact1Id, + 'SORT' => '100', + 'IS_PRIMARY' => 'N', + ], + ] + + )->isSuccess() + ); + + $this::assertCount(2, $this->dealContactService->itemsGet($dealId)->getDealContacts()); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\DealContact::delete + * @throws BaseException + * @throws TransportException + */ + public function testDelete(): void + { + $dealId = $this->dealService->add(['TITLE' => 'test deal'])->getId(); + $contact1Id = $this->contactService->add(['NAME' => 'test contact 1'], [])->getId(); + $contact2Id = $this->contactService->add(['NAME' => 'test contact 2'], [])->getId(); + + $this::assertGreaterThanOrEqual( + 1, + $this->dealContactService->add($dealId, $contact1Id, true)->getId() + ); + $this::assertGreaterThanOrEqual( + 1, + $this->dealContactService->add($dealId, $contact2Id, false)->getId() + ); + + $this::assertCount(2, $this->dealContactService->itemsGet($dealId)->getDealContacts()); + + $this::assertTrue($this->dealContactService->delete($dealId, $contact2Id)->isSuccess()); + + $this::assertCount(1, $this->dealContactService->itemsGet($dealId)->getDealContacts()); + } + + public function setUp(): void + { + $this->dealService = Fabric::getServiceBuilder()->getCRMScope()->deal(); + $this->dealContactService = Fabric::getServiceBuilder()->getCRMScope()->dealContact(); + $this->contactService = Fabric::getServiceBuilder()->getCRMScope()->contact(); + } +} \ No newline at end of file From 7ca7d683255c394d74972d2dbf84ee90e2a6e07f Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 1 Feb 2021 01:33:54 +0300 Subject: [PATCH 222/647] add deal contact service and test --- .../CRM/Deal/Result/DealContactItemResult.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/Services/CRM/Deal/Result/DealContactItemResult.php diff --git a/src/Services/CRM/Deal/Result/DealContactItemResult.php b/src/Services/CRM/Deal/Result/DealContactItemResult.php new file mode 100644 index 00000000..58a13ed6 --- /dev/null +++ b/src/Services/CRM/Deal/Result/DealContactItemResult.php @@ -0,0 +1,19 @@ + Date: Sun, 30 May 2021 17:57:20 +0300 Subject: [PATCH 223/647] add onApiCallMethod --- src/bitrix24.php | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/bitrix24.php b/src/bitrix24.php index 8cc3d040..51e5f373 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -143,6 +143,11 @@ class Bitrix24 implements iBitrix24 */ protected $_onExpiredToken; + /** + * @var callable callback after api method called + */ + protected $_onCallApiMethod; + /** * @var bool ssl verify for checking CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST */ @@ -204,6 +209,16 @@ public function setOnExpiredToken(callable $callback) $this->_onExpiredToken = $callback; } + /** + * Set function called after api method executed. Callback receives instance as first parameter, method name as second. + * + * @param callable $callback + */ + public function setOnCallApiMethod(callable $callback) + { + $this->_onCallApiMothod = $callback; + } + /** * Get a random string to sign protected api-call. Use salt for argument "state" in secure api-call * random string is a result of mt_rand function @@ -1114,8 +1129,13 @@ public function processBatchCalls($halt = 0, $delay = self::BATCH_DELAY) public function call($methodName, array $additionalParameters = array()) { try { - $result = $this->getWebhookUsage() ? $this->_call_webhook($methodName, $additionalParameters) - : $this->_call($methodName, $additionalParameters); + $result = $this->getWebhookUsage() ? $this->_call_webhook($methodName, $additionalParameters) + : $this->_call($methodName, $additionalParameters); + + if (is_callable($this->_onCallApiMothod)) { + call_user_func($this->_onCallApiMothod, $this, $methodName); + } + } catch (Bitrix24TokenIsExpiredException $e) { if (!is_callable($this->_onExpiredToken)) { throw $e; From 8b6426d06531ddb6458185853050cb0f92bf0864 Mon Sep 17 00:00:00 2001 From: camaxtly Date: Thu, 10 Jun 2021 08:23:58 +0300 Subject: [PATCH 224/647] fix error --- src/bitrix24.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bitrix24.php b/src/bitrix24.php index 51e5f373..6df97bbc 100644 --- a/src/bitrix24.php +++ b/src/bitrix24.php @@ -216,7 +216,7 @@ public function setOnExpiredToken(callable $callback) */ public function setOnCallApiMethod(callable $callback) { - $this->_onCallApiMothod = $callback; + $this->_onCallApiMethod = $callback; } /** @@ -1132,8 +1132,8 @@ public function call($methodName, array $additionalParameters = array()) $result = $this->getWebhookUsage() ? $this->_call_webhook($methodName, $additionalParameters) : $this->_call($methodName, $additionalParameters); - if (is_callable($this->_onCallApiMothod)) { - call_user_func($this->_onCallApiMothod, $this, $methodName); + if (is_callable($this->_onCallApiMethod)) { + call_user_func($this->_onCallApiMethod, $this, $methodName); } } catch (Bitrix24TokenIsExpiredException $e) { From f3b7489bf1d199ca1431c2696e0eb5a1ab4add9d Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 10 Nov 2021 18:38:37 +0300 Subject: [PATCH 225/647] add 8.x support --- CHANGELOG.md | 4 ++++ composer.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a2da028..e37d5712 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # bitrix24-php-sdk change log +## 2.0-alpha.3(10.11.2021) + +* add php8 version support + ## 2.0-alpha.2 (31.01.2021) * remove Travis CI and migrate to Github Actions diff --git a/composer.json b/composer.json index 58212036..c60644c0 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ } ], "require": { - "php": "7.4.*", + "php": "7.4.*|8.*", "ext-json": "*", "ext-curl": "*", "psr/log": "1.1.3", From 7beab5dcce01e1e65ce5f12b16847b13647fd83c Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 11 Nov 2021 19:17:01 +0300 Subject: [PATCH 226/647] add Product and integration test --- CHANGELOG.md | 1 + src/Services/CRM/CRMServiceBuilder.php | 18 +- .../CRM/Product/Result/ProductItemResult.php | 36 +++ .../CRM/Product/Result/ProductResult.php | 16 ++ .../CRM/Product/Result/ProductsResult.php | 31 +++ src/Services/CRM/Product/Service/Batch.php | 75 ++++++ src/Services/CRM/Product/Service/Product.php | 214 ++++++++++++++++++ .../CRM/Products/Service/Products.php | 107 --------- .../CRM/Products/Service/ProductsTest.php | 130 +++++++++++ 9 files changed, 520 insertions(+), 108 deletions(-) create mode 100644 src/Services/CRM/Product/Result/ProductItemResult.php create mode 100644 src/Services/CRM/Product/Result/ProductResult.php create mode 100644 src/Services/CRM/Product/Result/ProductsResult.php create mode 100644 src/Services/CRM/Product/Service/Batch.php create mode 100644 src/Services/CRM/Product/Service/Product.php delete mode 100644 src/Services/CRM/Products/Service/Products.php create mode 100644 tests/Integration/Services/CRM/Products/Service/ProductsTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index e37d5712..300d1941 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 2.0-alpha.3(10.11.2021) * add php8 version support +* change in scope «CRM» Product service and integration tests ## 2.0-alpha.2 (31.01.2021) diff --git a/src/Services/CRM/CRMServiceBuilder.php b/src/Services/CRM/CRMServiceBuilder.php index f55bde80..d8c2e0be 100644 --- a/src/Services/CRM/CRMServiceBuilder.php +++ b/src/Services/CRM/CRMServiceBuilder.php @@ -7,7 +7,7 @@ use Bitrix24\SDK\Services\AbstractServiceBuilder; use Bitrix24\SDK\Services\CRM\Contact; use Bitrix24\SDK\Services\CRM\Deal; -use Bitrix24\SDK\Services\CRM\Products; +use Bitrix24\SDK\Services\CRM\Product; use Bitrix24\SDK\Services\CRM\Settings; @@ -109,4 +109,20 @@ public function dealCategoryStage(): Deal\Service\DealCategoryStage return $this->serviceCache[__METHOD__]; } + + /** + * @return Product\Service\Product + */ + public function product(): Product\Service\Product + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Product\Service\Product( + new Product\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } } \ No newline at end of file diff --git a/src/Services/CRM/Product/Result/ProductItemResult.php b/src/Services/CRM/Product/Result/ProductItemResult.php new file mode 100644 index 00000000..9e894646 --- /dev/null +++ b/src/Services/CRM/Product/Result/ProductItemResult.php @@ -0,0 +1,36 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData()); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Product/Result/ProductsResult.php b/src/Services/CRM/Product/Result/ProductsResult.php new file mode 100644 index 00000000..1c9ba02c --- /dev/null +++ b/src/Services/CRM/Product/Result/ProductsResult.php @@ -0,0 +1,31 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { + $res[] = new ProductItemResult($item); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Product/Service/Batch.php b/src/Services/CRM/Product/Service/Batch.php new file mode 100644 index 00000000..81f82c41 --- /dev/null +++ b/src/Services/CRM/Product/Service/Batch.php @@ -0,0 +1,75 @@ + + * @throws BaseException + */ + public function list(array $order, array $filter, array $select, ?int $limit = null): Generator + { + $this->log->debug( + 'list', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'limit' => $limit, + ] + ); + foreach ($this->batch->getTraversableList('crm.product.list', $order, $filter, $select, $limit) as $key => $value) { + yield $key => new ProductItemResult($value); + } + } + + /** + * Batch adding product + * + * @param array $products + * + * @return Generator + */ + public function add(array $products): Generator + { + $items = []; + foreach ($products as $product) { + $items[] = [ + 'fields' => $product, + ]; + } + foreach ($this->batch->addEntityItems('crm.product.add', $items) as $key => $item) { + yield $key => new ProductItemResult( + [ + 'ID' => $item->getResult()->getResultData()[0], + ] + ); + } + } +} \ No newline at end of file diff --git a/src/Services/CRM/Product/Service/Product.php b/src/Services/CRM/Product/Service/Product.php new file mode 100644 index 00000000..c36e7d1b --- /dev/null +++ b/src/Services/CRM/Product/Service/Product.php @@ -0,0 +1,214 @@ +batch = $batch; + } + + /** + * Add new product + * + * @link https://training.bitrix24.com/rest_help/crm/products/crm_product_add.php + * + * @param array{ + * ID?: int, + * CATALOG_ID?: int, + * PRICE?: string, + * CURRENCY_ID?: string, + * NAME?: string, + * CODE?: string, + * DESCRIPTION?: string, + * DESCRIPTION_TYPE?: string, + * ACTIVE?: string, + * SECTION_ID?: int, + * SORT?: int, + * VAT_ID?: int, + * VAT_INCLUDED?: string, + * MEASURE?: int, + * XML_ID?: string, + * PREVIEW_PICTURE?: string, + * DETAIL_PICTURE?: string, + * DATE_CREATE?: string, + * TIMESTAMP_X?: string, + * MODIFIED_BY?: int, + * CREATED_BY?: int + * } $fields + * + * @return AddedItemResult + * @throws BaseException + * @throws TransportException + */ + public function add(array $fields): AddedItemResult + { + return new AddedItemResult( + $this->core->call( + 'crm.product.add', + [ + 'fields' => $fields, + ] + ) + ); + } + + /** + * Delete product by id + * + * @link https://training.bitrix24.com/rest_help/crm/products/crm_product_delete.php + * + * @param int $productId + * + * @return \Bitrix24\SDK\Core\Result\DeletedItemResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function delete(int $productId): DeletedItemResult + { + return new DeletedItemResult( + $this->core->call( + 'crm.product.delete', + [ + 'id' => $productId, + ] + ) + ); + } + + /** + * Returns a product by the product id. + * + * @link https://training.bitrix24.com/rest_help/crm/products/crm_product_get.php + * + * @param int $id + * + * @return \Bitrix24\SDK\Services\CRM\Product\Result\ProductResult + * @throws BaseException + * @throws TransportException + */ + public function get(int $id): ProductResult + { + return new ProductResult($this->core->call('crm.product.get', ['id' => $id])); + } + + /** + * Returns the description of the product fields, including user fields. + * + * @link https://training.bitrix24.com/rest_help/crm/products/crm_product_fields.php + * + * @return FieldsResult + * @throws BaseException + * @throws TransportException + */ + public function fields(): FieldsResult + { + return new FieldsResult($this->core->call('crm.product.fields')); + } + + /** + * Get list of product items. + * + * @link https://training.bitrix24.com/rest_help/crm/products/crm_product_list.php + * + * @param array $order - order of product items + * @param array $filter - filter array + * @param array $select = ['ID','CATALOG_ID','PRICE','CURRENCY_ID','NAME','CODE','DESCRIPTION','DESCRIPTION_TYPE','ACTIVE','SECTION_ID','SORT','VAT_ID','VAT_INCLUDED','MEASURE','XML_ID','PREVIEW_PICTURE','DETAIL_PICTURE','DATE_CREATE','TIMESTAMP_X','MODIFIED_BY','CREATED_BY'] + * @param int $startItem - entity number to start from (usually returned in 'next' field of previous 'crm.product.list' API call) + * + * @return ProductsResult + * @throws BaseException + * @throws TransportException + */ + public function list(array $order, array $filter, array $select, int $startItem = 0): ProductsResult + { + return new ProductsResult( + $this->core->call( + 'crm.deal.list', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $startItem, + ] + ) + ); + } + + /** + * Updates the specified (existing) product. + * + * @link https://training.bitrix24.com/rest_help/crm/products/crm_product_update.php + * + * @param int $id + * @param array{ + * ID?: int, + * CATALOG_ID?: int, + * PRICE?: string, + * CURRENCY_ID?: string, + * NAME?: string, + * CODE?: string, + * DESCRIPTION?: string, + * DESCRIPTION_TYPE?: string, + * ACTIVE?: string, + * SECTION_ID?: int, + * SORT?: int, + * VAT_ID?: int, + * VAT_INCLUDED?: string, + * MEASURE?: int, + * XML_ID?: string, + * PREVIEW_PICTURE?: string, + * DETAIL_PICTURE?: string, + * DATE_CREATE?: string, + * TIMESTAMP_X?: string, + * MODIFIED_BY?: int, + * CREATED_BY?: int + * } $fields + * + * @return UpdatedItemResult + * @throws BaseException + * @throws TransportException + */ + public function update(int $id, array $fields): UpdatedItemResult + { + return new UpdatedItemResult( + $this->core->call( + 'crm.product.update', + [ + 'id' => $id, + 'fields' => $fields, + ] + ) + ); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Products/Service/Products.php b/src/Services/CRM/Products/Service/Products.php deleted file mode 100644 index 9db66b13..00000000 --- a/src/Services/CRM/Products/Service/Products.php +++ /dev/null @@ -1,107 +0,0 @@ -log->debug('add.start', ['fields' => $fields]); - - $result = $this->core->call( - 'crm.product.add', - [ - 'fields' => $fields, - ] - ); - - $this->log->debug('add.finish'); - - return $result; - } - - /** - * @param int $productId - * - * @return Response - * @throws BaseException - * @throws TransportException - */ - public function delete(int $productId): Response - { - $this->log->debug( - 'delete.start', - [ - 'id' => $productId, - ] - ); - - $result = $this->core->call( - 'crm.product.delete', - [ - 'id' => $productId, - ] - ); - - - $this->log->debug('delete.finish'); - - return $result; - } - - /** - * @param array $order - * @param array $filter - * @param array $select - * @param int $startItem - * - * @return Response - * @throws BaseException - * @throws TransportException - */ - public function list(array $order, array $filter, array $select, int $startItem = 0): Response - { - $this->log->debug( - 'list.start', - [ - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'start' => $startItem, - ] - ); - - $result = $this->core->call( - 'crm.product.list', - [ - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'start' => $startItem, - ] - ); - - $this->log->debug('list.finish'); - - return $result; - } -} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Products/Service/ProductsTest.php b/tests/Integration/Services/CRM/Products/Service/ProductsTest.php new file mode 100644 index 00000000..099b80d7 --- /dev/null +++ b/tests/Integration/Services/CRM/Products/Service/ProductsTest.php @@ -0,0 +1,130 @@ +productService->add(['NAME' => 'test product'])->getId()); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers \Bitrix24\SDK\Services\CRM\Product\Service\Product::delete + */ + public function testDelete(): void + { + self::assertTrue($this->productService->delete($this->productService->add(['NAME' => 'test product'])->getId())->isSuccess()); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers \Bitrix24\SDK\Services\CRM\Product\Service\Product::get + */ + public function testGet(): void + { + $product = [ + 'NAME' => 'test product', + ]; + $addProductResult = $this->productService->get($this->productService->add($product)->getId()); + self::assertGreaterThan( + 1, + $addProductResult->product()->ID + ); + self::assertEquals( + $product['NAME'], + $addProductResult->product()->NAME + ); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Product\Service\Product::fields + * @throws BaseException + * @throws TransportException + */ + public function testFields(): void + { + self::assertIsArray($this->productService->fields()->getFieldsDescription()); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers \Bitrix24\SDK\Services\CRM\Product\Service\Product::list + */ + public function testList(): void + { + $this->productService->add(['NAME' => 'test']); + self::assertGreaterThanOrEqual(1, $this->productService->list([], [], ['ID', 'NAME'])->getDeals()); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers \Bitrix24\SDK\Services\CRM\Product\Service\Product::update + */ + public function testUpdate(): void + { + $product = $this->productService->add(['NAME' => 'test']); + $newName = 'test2'; + + self::assertTrue($this->productService->update($product->getId(), ['NAME' => $newName])->isSuccess()); + self::assertEquals($newName, $this->productService->get($product->getId())->product()->NAME); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Product\Service\Batch::list() + * @throws BaseException + * @throws TransportException + */ + public function testBatchList(): void + { + $this->productService->add(['NAME' => 'test product']); + $cnt = 0; + + foreach ($this->productService->batch->list([], ['>ID' => '1'], ['ID', 'NAME'], 1) as $item) { + $cnt++; + } + self::assertGreaterThanOrEqual(1, $cnt); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Product\Service\Batch::add() + */ + public function testBatchAdd(): void + { + $products = []; + for ($i = 1; $i < 60; $i++) { + $products[] = ['NAME' => 'NAME-' . $i]; + } + $cnt = 0; + foreach ($this->productService->batch->add($products) as $item) { + $cnt++; + } + + self::assertEquals(count($products), $cnt); + } + + public function setUp(): void + { + $this->productService = Fabric::getServiceBuilder()->getCRMScope()->product(); + } +} \ No newline at end of file From d5678eaeb28b28009da8e45ea6b3d19f3e38e9ad Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 12 Nov 2021 21:06:06 +0300 Subject: [PATCH 227/647] fix errors in product.list --- src/Services/CRM/Product/Result/ProductsResult.php | 2 +- src/Services/CRM/Product/Service/Product.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Services/CRM/Product/Result/ProductsResult.php b/src/Services/CRM/Product/Result/ProductsResult.php index 1c9ba02c..a3814d85 100644 --- a/src/Services/CRM/Product/Result/ProductsResult.php +++ b/src/Services/CRM/Product/Result/ProductsResult.php @@ -19,7 +19,7 @@ class ProductsResult extends AbstractResult * @return \Bitrix24\SDK\Services\CRM\Product\Result\ProductItemResult[] * @throws BaseException */ - public function getDeals(): array + public function getProducts(): array { $res = []; foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { diff --git a/src/Services/CRM/Product/Service/Product.php b/src/Services/CRM/Product/Service/Product.php index c36e7d1b..9a725eda 100644 --- a/src/Services/CRM/Product/Service/Product.php +++ b/src/Services/CRM/Product/Service/Product.php @@ -154,7 +154,7 @@ public function list(array $order, array $filter, array $select, int $startItem { return new ProductsResult( $this->core->call( - 'crm.deal.list', + 'crm.product.list', [ 'order' => $order, 'filter' => $filter, From b5df01fe956bf527f1d11e1f3c5977e582c6bb73 Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 12 Nov 2021 21:57:42 +0300 Subject: [PATCH 228/647] add AddedItemIdResultInterface --- CHANGELOG.md | 1 + .../Contracts/AddedItemIdResultInterface.php | 15 ++++++++ src/Core/Result/AddedItemBatchResult.php | 34 +++++++++++++++++++ src/Core/Result/AddedItemResult.php | 3 +- src/Services/CRM/Contact/Service/Batch.php | 9 ++--- src/Services/CRM/Deal/Service/Batch.php | 9 ++--- src/Services/CRM/Product/Service/Batch.php | 31 +++++++++++++---- 7 files changed, 82 insertions(+), 20 deletions(-) create mode 100644 src/Core/Contracts/AddedItemIdResultInterface.php create mode 100644 src/Core/Result/AddedItemBatchResult.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 300d1941..dc111a5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * add php8 version support * change in scope «CRM» Product service and integration tests +* add `AddedItemIdResultInterface` for batch-queries result ## 2.0-alpha.2 (31.01.2021) diff --git a/src/Core/Contracts/AddedItemIdResultInterface.php b/src/Core/Contracts/AddedItemIdResultInterface.php new file mode 100644 index 00000000..e9adcf78 --- /dev/null +++ b/src/Core/Contracts/AddedItemIdResultInterface.php @@ -0,0 +1,15 @@ +responseData = $responseData; + } + + /** + * @return \Bitrix24\SDK\Core\Response\DTO\ResponseData + */ + public function getResponseData(): ResponseData + { + return $this->responseData; + } + + public function getId(): int + { + return (int)$this->getResponseData()->getResult()->getResultData()[0]; + } +} \ No newline at end of file diff --git a/src/Core/Result/AddedItemResult.php b/src/Core/Result/AddedItemResult.php index 5385fe1b..fad8366d 100644 --- a/src/Core/Result/AddedItemResult.php +++ b/src/Core/Result/AddedItemResult.php @@ -4,6 +4,7 @@ namespace Bitrix24\SDK\Core\Result; +use Bitrix24\SDK\Core\Contracts\AddedItemIdResultInterface; use Bitrix24\SDK\Core\Exceptions\BaseException; /** @@ -11,7 +12,7 @@ * * @package Bitrix24\SDK\Core\Result */ -class AddedItemResult extends AbstractResult +class AddedItemResult extends AbstractResult implements AddedItemIdResultInterface { /** * @return int diff --git a/src/Services/CRM/Contact/Service/Batch.php b/src/Services/CRM/Contact/Service/Batch.php index 9eceb42a..2271b8ac 100644 --- a/src/Services/CRM/Contact/Service/Batch.php +++ b/src/Services/CRM/Contact/Service/Batch.php @@ -5,6 +5,7 @@ namespace Bitrix24\SDK\Services\CRM\Contact\Service; use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AddedItemBatchResult; use Bitrix24\SDK\Services\AbstractBatchService; use Bitrix24\SDK\Services\CRM\Contact\Result\ContactItemResult; use Generator; @@ -193,7 +194,7 @@ public function list(array $order, array $filter, array $select, ?int $limit = n * IM?: string, * }> $contacts * - * @return Generator + * @return Generator|AddedItemBatchResult[] */ public function add(array $contacts): Generator { @@ -204,11 +205,7 @@ public function add(array $contacts): Generator ]; } foreach ($this->batch->addEntityItems('crm.contact.add', $items) as $key => $item) { - yield $key => new ContactItemResult( - [ - 'ID' => $item->getResult()->getResultData()[0], - ] - ); + yield $key => new AddedItemBatchResult($item); } } } \ No newline at end of file diff --git a/src/Services/CRM/Deal/Service/Batch.php b/src/Services/CRM/Deal/Service/Batch.php index 414775fd..9ba2dc9e 100644 --- a/src/Services/CRM/Deal/Service/Batch.php +++ b/src/Services/CRM/Deal/Service/Batch.php @@ -6,6 +6,7 @@ use Bitrix24\SDK\Core\Contracts\BatchInterface; use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AddedItemBatchResult; use Bitrix24\SDK\Services\CRM\Deal\Result\DealItemResult; use Generator; use Psr\Log\LoggerInterface; @@ -191,7 +192,7 @@ public function list(array $order, array $filter, array $select, ?int $limit = n * UTM_TERM?: string, * }> $deals * - * @return Generator + * @return Generator|AddedItemBatchResult[] */ public function add(array $deals): Generator { @@ -202,11 +203,7 @@ public function add(array $deals): Generator ]; } foreach ($this->batch->addEntityItems('crm.deal.add', $items) as $key => $item) { - yield $key => new DealItemResult( - [ - 'ID' => $item->getResult()->getResultData()[0], - ] - ); + yield $key => new AddedItemBatchResult($item); } } } \ No newline at end of file diff --git a/src/Services/CRM/Product/Service/Batch.php b/src/Services/CRM/Product/Service/Batch.php index 81f82c41..1fc755f4 100644 --- a/src/Services/CRM/Product/Service/Batch.php +++ b/src/Services/CRM/Product/Service/Batch.php @@ -5,6 +5,7 @@ namespace Bitrix24\SDK\Services\CRM\Product\Service; 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; @@ -25,7 +26,7 @@ class Batch extends AbstractBatchService * @param array{ * ID?: int, * } $filter - * @param array $select = ['ID'] + * @param array $select = ['ID','CATALOG_ID','PRICE','CURRENCY_ID','NAME','CODE','DESCRIPTION','DESCRIPTION_TYPE','ACTIVE','SECTION_ID','SORT','VAT_ID','VAT_INCLUDED','MEASURE','XML_ID','PREVIEW_PICTURE','DETAIL_PICTURE','DATE_CREATE','TIMESTAMP_X','MODIFIED_BY','CREATED_BY'] * @param int|null $limit * * @return Generator @@ -52,9 +53,29 @@ public function list(array $order, array $filter, array $select, ?int $limit = n * * @param array $products * - * @return Generator + * @return Generator|AddedItemBatchResult[] */ public function add(array $products): Generator { @@ -65,11 +86,7 @@ public function add(array $products): Generator ]; } foreach ($this->batch->addEntityItems('crm.product.add', $items) as $key => $item) { - yield $key => new ProductItemResult( - [ - 'ID' => $item->getResult()->getResultData()[0], - ] - ); + yield $key => new AddedItemBatchResult($item); } } } \ No newline at end of file From 1ea1d7f326ec0f9df1dddae758ba6162e5f9bb11 Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 12 Nov 2021 23:20:12 +0300 Subject: [PATCH 229/647] fix method name in ContactsResult --- CHANGELOG.md | 1 + src/Services/CRM/Contact/Result/ContactsResult.php | 2 +- tests/Integration/Services/CRM/Contact/Service/ContactTest.php | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc111a5b..d2f4a0b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * add php8 version support * change in scope «CRM» Product service and integration tests * add `AddedItemIdResultInterface` for batch-queries result +* fix method name in `ContactsResult` ## 2.0-alpha.2 (31.01.2021) diff --git a/src/Services/CRM/Contact/Result/ContactsResult.php b/src/Services/CRM/Contact/Result/ContactsResult.php index 3a147f1c..2e8748f2 100644 --- a/src/Services/CRM/Contact/Result/ContactsResult.php +++ b/src/Services/CRM/Contact/Result/ContactsResult.php @@ -19,7 +19,7 @@ class ContactsResult extends AbstractResult * @return ContactItemResult[] * @throws BaseException */ - public function contacts(): array + public function getContacts(): array { $res = []; foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { diff --git a/tests/Integration/Services/CRM/Contact/Service/ContactTest.php b/tests/Integration/Services/CRM/Contact/Service/ContactTest.php index afe39c07..a98af97d 100644 --- a/tests/Integration/Services/CRM/Contact/Service/ContactTest.php +++ b/tests/Integration/Services/CRM/Contact/Service/ContactTest.php @@ -70,7 +70,7 @@ public function testGet(): void public function testList(): void { $this->contactService->add(['NAME' => 'test contact']); - self::assertGreaterThanOrEqual(1, $this->contactService->list([''], [''], ['ID', 'NAME'], 0)->contacts()); + self::assertGreaterThanOrEqual(1, $this->contactService->list([''], [''], ['ID', 'NAME'], 0)->getContacts()); } /** From 5a268d7aba1989a444e97c6465cb69a8650b3313 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 13 Nov 2021 21:21:36 +0300 Subject: [PATCH 230/647] fix method name in ContactsResult --- CHANGELOG.md | 3 ++ composer.json | 4 +-- src/Core/ApiClient.php | 31 +++++------------ src/Core/ApiLevelErrorHandler.php | 9 ++--- src/Core/Contracts/ApiClientInterface.php | 36 +++++++++++++++++++ src/Core/Contracts/CoreInterface.php | 5 +++ src/Core/Core.php | 27 +++++++-------- src/Core/CoreBuilder.php | 42 ++++++----------------- src/Core/Credentials/Credentials.php | 29 +++++----------- src/Services/AbstractService.php | 6 ++-- 10 files changed, 94 insertions(+), 98 deletions(-) create mode 100644 src/Core/Contracts/ApiClientInterface.php diff --git a/CHANGELOG.md b/CHANGELOG.md index d2f4a0b5..6662182c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ * change in scope «CRM» Product service and integration tests * add `AddedItemIdResultInterface` for batch-queries result * fix method name in `ContactsResult` +* add interface `ApiClientInterface` +* bump phpunit version +* bump phpstan version ## 2.0-alpha.2 (31.01.2021) diff --git a/composer.json b/composer.json index c60644c0..9492c824 100644 --- a/composer.json +++ b/composer.json @@ -32,8 +32,8 @@ "symfony/console": "5.2.*", "symfony/dotenv": "5.2.*", "symfony/debug-bundle": "5.2.*", - "phpstan/phpstan": "0.12.59", - "phpunit/phpunit": "9.3.*", + "phpstan/phpstan": "1.1.*", + "phpunit/phpunit": "9.5.*", "roave/security-advisories": "dev-master" }, "autoload": { diff --git a/src/Core/ApiClient.php b/src/Core/ApiClient.php index 72a5d626..5ae6cf70 100644 --- a/src/Core/ApiClient.php +++ b/src/Core/ApiClient.php @@ -4,6 +4,7 @@ namespace Bitrix24\SDK\Core; +use Bitrix24\SDK\Core\Contracts\ApiClientInterface; use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; use Bitrix24\SDK\Core\Response\DTO\RenewedAccessToken; use Psr\Log\LoggerInterface; @@ -11,25 +12,11 @@ use Symfony\Contracts\HttpClient\HttpClientInterface; use Symfony\Contracts\HttpClient\ResponseInterface; -/** - * Class ApiClient - * - * @package Bitrix24\SDK\Core - */ -class ApiClient +class ApiClient implements ApiClientInterface { - /** - * @var HttpClientInterface - */ - protected $client; - /** - * @var LoggerInterface - */ - protected $logger; - /** - * @var Credentials\Credentials - */ - protected $credentials; + protected HttpClientInterface $client; + protected LoggerInterface $logger; + protected Credentials\Credentials $credentials; /** * @const string */ @@ -90,12 +77,12 @@ public function getCredentials(): Credentials\Credentials */ public function getNewAccessToken(): RenewedAccessToken { - $this->logger->debug(sprintf('getNewAccessToken.start')); + $this->logger->debug('getNewAccessToken.start'); if ($this->getCredentials()->getApplicationProfile() === null) { - throw new InvalidArgumentException(sprintf('application profile not set')); + throw new InvalidArgumentException('application profile not set'); } if ($this->getCredentials()->getAccessToken() === null) { - throw new InvalidArgumentException(sprintf('access token in credentials not set')); + throw new InvalidArgumentException('access token in credentials not set'); } $method = 'GET'; @@ -119,7 +106,7 @@ public function getNewAccessToken(): RenewedAccessToken $result = $response->toArray(false); $newAccessToken = RenewedAccessToken::initFromArray($result); - $this->logger->debug(sprintf('getNewAccessToken.finish')); + $this->logger->debug('getNewAccessToken.finish'); return $newAccessToken; } diff --git a/src/Core/ApiLevelErrorHandler.php b/src/Core/ApiLevelErrorHandler.php index 0044cda0..238ed730 100644 --- a/src/Core/ApiLevelErrorHandler.php +++ b/src/Core/ApiLevelErrorHandler.php @@ -18,10 +18,7 @@ */ class ApiLevelErrorHandler { - /** - * @var LoggerInterface - */ - protected $logger; + protected LoggerInterface $logger; protected const ERROR_KEY = 'error'; protected const ERROR_DESCRIPTION_KEY = 'error_description'; @@ -58,9 +55,9 @@ public function handle(array $responseBody): void ); switch ($errorCode) { case 'query_limit_exceeded': - throw new QueryLimitExceededException(sprintf('query limit exceeded - too many requests')); + throw new QueryLimitExceededException('query limit exceeded - too many requests'); case 'error_method_not_found': - throw new MethodNotFoundException(sprintf('api method not found')); + throw new MethodNotFoundException('api method not found'); default: throw new BaseException(sprintf('%s - %s', $errorCode, $errorDescription)); } diff --git a/src/Core/Contracts/ApiClientInterface.php b/src/Core/Contracts/ApiClientInterface.php new file mode 100644 index 00000000..f4782170 --- /dev/null +++ b/src/Core/Contracts/ApiClientInterface.php @@ -0,0 +1,36 @@ +apiClient; + } } \ No newline at end of file diff --git a/src/Core/CoreBuilder.php b/src/Core/CoreBuilder.php index 1d147535..a56c7b08 100644 --- a/src/Core/CoreBuilder.php +++ b/src/Core/CoreBuilder.php @@ -4,6 +4,7 @@ namespace Bitrix24\SDK\Core; +use Bitrix24\SDK\Core\Contracts\ApiClientInterface; use Bitrix24\SDK\Core\Contracts\CoreInterface; use Bitrix24\SDK\Core\Credentials\Credentials; use Bitrix24\SDK\Core\Credentials\WebhookUrl; @@ -22,34 +23,13 @@ */ class CoreBuilder { - /** - * @var ApiClient|null - */ - protected $apiClient; - /** - * @var HttpClientInterface - */ - protected $httpClient; - /** - * @var EventDispatcherInterface - */ - protected $eventDispatcher; - /** - * @var LoggerInterface - */ - protected $logger; - /** - * @var WebhookUrl|null - */ - protected $webhookUrl; - /** - * @var Credentials|null - */ - protected $credentials; - /** - * @var ApiLevelErrorHandler - */ - protected $apiLevelErrorHandler; + protected ?ApiClientInterface $apiClient; + protected HttpClientInterface $httpClient; + protected EventDispatcherInterface $eventDispatcher; + protected LoggerInterface $logger; + protected ?WebhookUrl $webhookUrl; + protected ?Credentials $credentials; + protected ApiLevelErrorHandler $apiLevelErrorHandler; /** * CoreBuilder constructor. @@ -83,11 +63,11 @@ public function withWebhookUrl(string $webhookUrl): self } /** - * @param ApiClient $apiClient + * @param ApiClientInterface $apiClient * * @return $this */ - public function withApiClient(ApiClient $apiClient): self + public function withApiClient(ApiClientInterface $apiClient): self { $this->apiClient = $apiClient; @@ -127,7 +107,7 @@ public function build(): CoreInterface if ($this->webhookUrl !== null) { $this->credentials = Credentials::createForWebHook($this->webhookUrl); } elseif ($this->credentials === null) { - throw new InvalidArgumentException(sprintf('you must set webhook url or oauth credentials')); + throw new InvalidArgumentException('you must set webhook url or oauth credentials'); } if ($this->apiClient === null) { diff --git a/src/Core/Credentials/Credentials.php b/src/Core/Credentials/Credentials.php index 4d367dad..ed868228 100644 --- a/src/Core/Credentials/Credentials.php +++ b/src/Core/Credentials/Credentials.php @@ -11,23 +11,10 @@ */ class Credentials { - /** - * @var WebhookUrl|null - */ - protected $webhookUrl; - /** - * @var AccessToken|null - */ - protected $accessToken; - /** - * @var ApplicationProfile|null - */ - protected $applicationProfile; - - /** - * @var string|null - */ - protected $domainUrl; + protected ?WebhookUrl $webhookUrl; + protected ?AccessToken $accessToken; + protected ?ApplicationProfile $applicationProfile; + protected ?string $domainUrl; /** * Credentials constructor. @@ -48,10 +35,10 @@ public function __construct( $this->applicationProfile = $applicationProfile; $this->domainUrl = $domainUrl; if ($this->accessToken === null && $this->webhookUrl === null) { - throw new \LogicException(sprintf('you must set on of auth type: webhook or OAuth 2.0')); + 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(sprintf('for oauth type you must set domain url')); + throw new \LogicException('for oauth type you must set domain url'); } } @@ -77,7 +64,9 @@ public function getApplicationProfile(): ?ApplicationProfile public function getDomainUrl(): string { if ($this->getWebhookUrl() !== null) { - $url = parse_url($this->getWebhookUrl()->getUrl())['host']; + $arUrl = parse_url($this->getWebhookUrl()->getUrl()); + + $url = sprintf('%s://%s', $arUrl['scheme'], $arUrl['host']); } else { $url = $this->domainUrl; } diff --git a/src/Services/AbstractService.php b/src/Services/AbstractService.php index c4be48a3..cf20323f 100644 --- a/src/Services/AbstractService.php +++ b/src/Services/AbstractService.php @@ -4,7 +4,6 @@ namespace Bitrix24\SDK\Services; -use Bitrix24\SDK\Core\Contracts\BatchInterface; use Bitrix24\SDK\Core\Contracts\CoreInterface; use Psr\Log\LoggerInterface; @@ -15,7 +14,10 @@ */ abstract class AbstractService { - protected CoreInterface $core; + /** + * @property-read CoreInterface $core + */ + public CoreInterface $core; protected LoggerInterface $log; /** From cabcede766f650f47a305fdded7170fd5ce40d95 Mon Sep 17 00:00:00 2001 From: Mesilov Maxim Date: Sun, 14 Nov 2021 01:53:13 +0300 Subject: [PATCH 231/647] fix method name in ContactsResult Signed-off-by: mesilov --- CHANGELOG.md | 1 + src/Services/CRM/Contact/Service/Contact.php | 60 +++++++++++++++++++ .../CRM/Contact/Service/ContactTest.php | 23 +++++++ 3 files changed, 84 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6662182c..e2cd2bcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * add php8 version support * change in scope «CRM» Product service and integration tests * add `AddedItemIdResultInterface` for batch-queries result +* add method `countByFilter` for CRM.Contact entity * fix method name in `ContactsResult` * add interface `ApiClientInterface` * bump phpunit version diff --git a/src/Services/CRM/Contact/Service/Contact.php b/src/Services/CRM/Contact/Service/Contact.php index d779bf31..b3a7e1bc 100644 --- a/src/Services/CRM/Contact/Service/Contact.php +++ b/src/Services/CRM/Contact/Service/Contact.php @@ -373,4 +373,64 @@ public function update(int $contactId, array $fields, array $params): UpdatedIte ) ); } + + /** + * @param array{ + * ID?: int, + * HONORIFIC?: string, + * NAME?: string, + * SECOND_NAME?: string, + * LAST_NAME?: string, + * PHOTO?: string, + * BIRTHDATE?: string, + * TYPE_ID?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: string, + * POST?: string, + * ADDRESS?: string, + * ADDRESS_2?: string, + * ADDRESS_CITY?: string, + * ADDRESS_POSTAL_CODE?: string, + * ADDRESS_REGION?: string, + * ADDRESS_PROVINCE?: string, + * ADDRESS_COUNTRY?: string, + * ADDRESS_COUNTRY_CODE?: string, + * ADDRESS_LOC_ADDR_ID?: int, + * COMMENTS?: string, + * OPENED?: string, + * EXPORT?: string, + * HAS_PHONE?: string, + * HAS_EMAIL?: string, + * HAS_IMOL?: string, + * ASSIGNED_BY_ID?: string, + * CREATED_BY_ID?: string, + * MODIFY_BY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * COMPANY_ID?: string, + * COMPANY_IDS?: string, + * LEAD_ID?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * ORIGIN_VERSION?: string, + * FACE_ID?: int, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string, + * PHONE?: string, + * EMAIL?: string, + * WEB?: string, + * IM?: string, + * } $filter + * + * @return int + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function countByFilter(array $filter = []): int + { + return $this->list([], $filter, ['ID'], 1)->getCoreResponse()->getResponseData()->getPagination()->getTotal(); + } } \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Contact/Service/ContactTest.php b/tests/Integration/Services/CRM/Contact/Service/ContactTest.php index a98af97d..1be0b5e4 100644 --- a/tests/Integration/Services/CRM/Contact/Service/ContactTest.php +++ b/tests/Integration/Services/CRM/Contact/Service/ContactTest.php @@ -116,6 +116,29 @@ public function testBatchAdd(): void self::assertEquals(count($contacts), $cnt); } + /** + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function testCountByFilter(): void + { + $totalBefore = $this->contactService->countByFilter(); + + $newContactsCount = 70; + + $contacts = []; + for ($i = 1; $i <= $newContactsCount; $i++) { + $contacts[] = ['NAME' => 'name-' . $i]; + } + + foreach ($this->contactService->batch->add($contacts) as $item) { + } + + $totalAfter = $this->contactService->countByFilter(); + + $this->assertEquals($totalBefore + $newContactsCount, $totalAfter); + } + public function setUp(): void { $this->contactService = Fabric::getServiceBuilder()->getCRMScope()->contact(); From 6b6392b9f1d377339491e0adecccd3e7701f5512 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 14 Nov 2021 11:34:16 +0300 Subject: [PATCH 232/647] update changelog Signed-off-by: mesilov --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2cd2bcb..b4d06afa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # bitrix24-php-sdk change log -## 2.0-alpha.3(10.11.2021) +## 2.0-alpha.3(14.11.2021) * add php8 version support * change in scope «CRM» Product service and integration tests @@ -34,6 +34,9 @@ * add OAuth 2.0 support * add Events support +## 0.1.0 (14.11.2021) +branch version 1.x – bugfix and security releases only + ## 0.7.0 (11.07.2020) * add arguments in method `Bitrix24\Bizproc\Robot::add` for return results support From 6a273b0d151f96929046ba59348dfe6de069bf91 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 14 Nov 2021 11:41:44 +0300 Subject: [PATCH 233/647] fix errors in tests and stubs Signed-off-by: mesilov --- tests/Unit/Stubs/NullCore.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/Unit/Stubs/NullCore.php b/tests/Unit/Stubs/NullCore.php index 9ed5a9f2..494c0c3e 100644 --- a/tests/Unit/Stubs/NullCore.php +++ b/tests/Unit/Stubs/NullCore.php @@ -4,10 +4,15 @@ namespace Bitrix24\SDK\Tests\Unit\Stubs; +use Bitrix24\SDK\Core\ApiClient; use Bitrix24\SDK\Core\Commands\Command; +use Bitrix24\SDK\Core\Contracts\ApiClientInterface; use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Credentials; +use Bitrix24\SDK\Core\Credentials\WebhookUrl; use Bitrix24\SDK\Core\Response\Response; use Psr\Log\NullLogger; +use Symfony\Component\HttpClient\MockHttpClient; use Symfony\Component\HttpClient\Response\MockResponse; /** @@ -28,4 +33,9 @@ public function call(string $apiMethod, array $parameters = []): Response { return new Response(new MockResponse(''), new Command('', []), new NullLogger()); } + + public function getApiClient(): ApiClientInterface + { + return new ApiClient(Credentials::createForWebHook(new WebhookUrl('')), new MockHttpClient(), new NullLogger()); + } } \ No newline at end of file From 327c8a2efb292ed8c8e8a26d17c80eebb461b6a1 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 14 Nov 2021 11:59:27 +0300 Subject: [PATCH 234/647] fix error in integration test Signed-off-by: mesilov --- .../Integration/Services/CRM/Products/Service/ProductsTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Integration/Services/CRM/Products/Service/ProductsTest.php b/tests/Integration/Services/CRM/Products/Service/ProductsTest.php index 099b80d7..b58f0ea4 100644 --- a/tests/Integration/Services/CRM/Products/Service/ProductsTest.php +++ b/tests/Integration/Services/CRM/Products/Service/ProductsTest.php @@ -73,7 +73,7 @@ public function testFields(): void public function testList(): void { $this->productService->add(['NAME' => 'test']); - self::assertGreaterThanOrEqual(1, $this->productService->list([], [], ['ID', 'NAME'])->getDeals()); + self::assertGreaterThanOrEqual(1, $this->productService->list([], [], ['ID', 'NAME'])->getProducts()); } /** From bdbc52b47fdcc796d47eee41555f146ed45c4d74 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 25 Nov 2021 00:08:02 +0300 Subject: [PATCH 235/647] bump dependencies versions Signed-off-by: mesilov --- CHANGELOG.md | 11 +++++++++++ composer.json | 8 ++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4d06afa..652ff935 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # bitrix24-php-sdk change log +## 2.0-alpha.4(25.11.2021) + +### Changed +* switch `symfony/http-client` to `5.3` version requirement. +* switch `symfony/http-client-contracts` to `^2.4` version requirement. +* switch `symfony/event-dispatcher` to `5.3.*` version requirement. +* switch `ramsey/uuid` to `^4.0` version requirement. + +### Fixed +* issue [Несовместимость с Laravel 8 #224](https://github.com/mesilov/bitrix24-php-sdk/issues/224) + ## 2.0-alpha.3(14.11.2021) * add php8 version support diff --git a/composer.json b/composer.json index 9492c824..458fb99e 100644 --- a/composer.json +++ b/composer.json @@ -22,10 +22,10 @@ "ext-curl": "*", "psr/log": "1.1.3", "fig/http-message-util": "1.1.*", - "symfony/http-client": "5.2.*", - "symfony/http-client-contracts": "^2.1", - "symfony/event-dispatcher": "5.2.*", - "ramsey/uuid": "^3.9.3" + "symfony/http-client": "5.3.*", + "symfony/http-client-contracts": "^2.4", + "symfony/event-dispatcher": "5.3.*", + "ramsey/uuid": "^4.0" }, "require-dev": { "monolog/monolog": "2.1.*", From c485cc3fb2576aa7e99b607e06b2009755400311 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 25 Nov 2021 00:56:20 +0300 Subject: [PATCH 236/647] delete old files Signed-off-by: mesilov --- CHANGELOG.md | 24 +++++-- src/bitrix24.php | 0 src/classes/crm/company/userfield.php | 97 --------------------------- src/classes/crm/contact/contact.php | 0 src/classes/crm/product/property.php | 0 src/classes/user/user.php | 0 6 files changed, 19 insertions(+), 102 deletions(-) delete mode 100644 src/bitrix24.php delete mode 100644 src/classes/crm/company/userfield.php delete mode 100644 src/classes/crm/contact/contact.php delete mode 100644 src/classes/crm/product/property.php delete mode 100644 src/classes/user/user.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 652ff935..b7dbebe9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,17 +1,30 @@ # bitrix24-php-sdk change log -## 2.0-alpha.4(25.11.2021) +## 2.0-alpha.5 – 26.11.2021 + +### Added + +* add method `countByFilter` for all services, see + issue [Добавить для всех сущностей метод подсчёта количества элементов по фильтру #228](https://github.com/mesilov/bitrix24-php-sdk/issues/228) + +### Removed + +* remove all `0.*` and `1.*` code from `2.*` branch + +## 2.0-alpha.4 – 25.11.2021 ### Changed + * switch `symfony/http-client` to `5.3` version requirement. * switch `symfony/http-client-contracts` to `^2.4` version requirement. * switch `symfony/event-dispatcher` to `5.3.*` version requirement. * switch `ramsey/uuid` to `^4.0` version requirement. - + ### Fixed + * issue [Несовместимость с Laravel 8 #224](https://github.com/mesilov/bitrix24-php-sdk/issues/224) -## 2.0-alpha.3(14.11.2021) +## 2.0-alpha.3 – 14.11.2021 * add php8 version support * change in scope «CRM» Product service and integration tests @@ -22,7 +35,7 @@ * bump phpunit version * bump phpstan version -## 2.0-alpha.2 (31.01.2021) +## 2.0-alpha.2 – 31.01.2021 * remove Travis CI and migrate to Github Actions * add unit-tests in independent github action @@ -37,7 +50,7 @@ * add in scope «IM» IM service and integration test * add in default scope «Main» default service -## 2.0-alpha.1 (11.07.2020) +## 2.0-alpha.1 – 11.07.2020 * remove all v1 code * migrate to Symfony HttpClient @@ -46,6 +59,7 @@ * add Events support ## 0.1.0 (14.11.2021) + branch version 1.x – bugfix and security releases only ## 0.7.0 (11.07.2020) diff --git a/src/bitrix24.php b/src/bitrix24.php deleted file mode 100644 index e69de29b..00000000 diff --git a/src/classes/crm/company/userfield.php b/src/classes/crm/company/userfield.php deleted file mode 100644 index 2b9eb435..00000000 --- a/src/classes/crm/company/userfield.php +++ /dev/null @@ -1,97 +0,0 @@ -client->call( - 'crm.company.userfield.list', - array( - 'order' => $order, - 'filter'=> $filter - ) - ); - return $fullResult; - } - - /** - * Get item userfield - * @link https://dev.1c-bitrix.ru/rest_help/crm/company/crm_company_userfield_get.php - * @param integer $userfieldId - company userfield id - * @return array - */ - public function get($userfieldId) - { - $fullResult = $this->client->call( - 'crm.company.userfield.get', - array('id' => $userfieldId) - ); - return $fullResult; - } - - /** - * Delete userfield - * @link https://dev.1c-bitrix.ru/rest_help/crm/company/crm_company_userfield_delete.php - * @param integer $userfieldId - company userfield id - * @return array - */ - public function delete($userfieldId) - { - $fullResult = $this->client->call( - 'crm.company.userfield.delete', - array('id' => $userfieldId) - ); - return $fullResult; - } - - /** - * Add a new userfield to company - * @param array $fields array of fields - * @link https://dev.1c-bitrix.ru/rest_help/crm/company/crm_company_userfield_add.php - * @return array - */ - public function add($fields = array()) - { - $fullResult = $this->client->call( - 'crm.company.userfield.add', - array('fields' => $fields) - ); - return $fullResult; - } - - - /** - * Updates userfield - * - * @param $id - * @param array $fields - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/company/crm_company_userfield_update.php - * @return array - */ - public function update($id, $fields = array()) - { - $fullResult = $this->client->call( - 'crm.company.userfield.update', - array( - 'id' => $id, - 'fields' => $fields - ) - ); - - return $fullResult; - } -} diff --git a/src/classes/crm/contact/contact.php b/src/classes/crm/contact/contact.php deleted file mode 100644 index e69de29b..00000000 diff --git a/src/classes/crm/product/property.php b/src/classes/crm/product/property.php deleted file mode 100644 index e69de29b..00000000 diff --git a/src/classes/user/user.php b/src/classes/user/user.php deleted file mode 100644 index e69de29b..00000000 From 2ff2bbb1541f132fb4e1ee365afe73d2518e7120 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 25 Nov 2021 00:59:41 +0300 Subject: [PATCH 237/647] try to fix phpstan with phpunit Signed-off-by: mesilov --- .github/workflows/phpstan.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index 1869b179..64c98bc0 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -14,6 +14,16 @@ jobs: - name: "Checkout" uses: actions/checkout@v2 + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + coverage: "none" + php-version: "${{ matrix.php-version }}" + + - name: "Install dependencies" + run: | + composer update ${{ env.COMPOSER_FLAGS }} + - name: PHPStan uses: docker://oskarstark/phpstan-ga with: From 00d9907fa4d4a1a7ece7e58b04fbae46dd344506 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 25 Nov 2021 01:01:39 +0300 Subject: [PATCH 238/647] try to fix phpstan with phpunit2 Signed-off-by: mesilov --- .github/workflows/phpstan.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index 64c98bc0..f76dc67b 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -2,6 +2,9 @@ on: push: pull_request: +env: + COMPOSER_FLAGS: "--ansi --no-interaction --no-progress --prefer-dist" + name: PHPStan checks jobs: @@ -10,6 +13,12 @@ jobs: runs-on: ubuntu-latest + strategy: + matrix: + php-version: + - "7.4" + dependencies: [ highest ] + steps: - name: "Checkout" uses: actions/checkout@v2 From f23a448f4c9c03ace177427272601d1eaa7685f6 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 25 Nov 2021 01:12:21 +0300 Subject: [PATCH 239/647] try to fix phpstan with phpunit3 Signed-off-by: mesilov --- .github/workflows/phpstan.yml | 36 +++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index f76dc67b..5b9859ae 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -2,38 +2,42 @@ on: push: pull_request: -env: - COMPOSER_FLAGS: "--ansi --no-interaction --no-progress --prefer-dist" - name: PHPStan checks jobs: - phpstan: - name: PHPStan - - runs-on: ubuntu-latest + static-analysis: + name: "PHPStan" + runs-on: "ubuntu-latest" strategy: + fail-fast: false matrix: php-version: - "7.4" - dependencies: [ highest ] + - "8.0" + dependencies: + - "lowest" + - "highest" steps: - name: "Checkout" - uses: actions/checkout@v2 + uses: "actions/checkout@v2" - name: "Install PHP" uses: "shivammathur/setup-php@v2" with: coverage: "none" php-version: "${{ matrix.php-version }}" + extensions: mbstring + tools: composer:v2 - - name: "Install dependencies" - run: | - composer update ${{ env.COMPOSER_FLAGS }} + - name: "Install lowest dependencies" + if: ${{ matrix.dependencies == 'lowest' }} + run: "composer update --prefer-lowest --no-interaction --no-progress --no-suggest" - - name: PHPStan - uses: docker://oskarstark/phpstan-ga - with: - args: analyse \ No newline at end of file + - name: "Install highest dependencies" + if: ${{ matrix.dependencies == 'highest' }} + run: "composer update --no-interaction --no-progress --no-suggest" + + - name: "PHPStan" + run: "composer phpstan-analyse" \ No newline at end of file From 267df06137fd0cce178af3d9dbc7c4d075ae343b Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 25 Nov 2021 01:14:39 +0300 Subject: [PATCH 240/647] remove tests from phpstan check Signed-off-by: mesilov --- phpstan.neon.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 31d2ac83..8fe7e307 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -2,6 +2,6 @@ parameters: level: 1 paths: - src/ - - tests/ +# - tests/ bootstrapFiles: - tests/bootstrap.php \ No newline at end of file From e64546c7525ba8a17e949b75f812163c018e3753 Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 26 Nov 2021 23:16:11 +0300 Subject: [PATCH 241/647] fix phpstan errors Signed-off-by: mesilov --- src/Core/Batch.php | 2 +- src/Services/CRM/Product/Service/Batch.php | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Core/Batch.php b/src/Core/Batch.php index 88b042ef..b53f7216 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -544,7 +544,7 @@ private function convertToApiCommands(): array $apiCommands = []; foreach ($this->commands as $itemCommand) { /** - * @var $itemCommand Command + * @var Command $itemCommand */ $apiCommands[$itemCommand->getName() ?? $itemCommand->getUuid()->toString()] = sprintf( '%s?%s', diff --git a/src/Services/CRM/Product/Service/Batch.php b/src/Services/CRM/Product/Service/Batch.php index 1fc755f4..2539ba79 100644 --- a/src/Services/CRM/Product/Service/Batch.php +++ b/src/Services/CRM/Product/Service/Batch.php @@ -20,11 +20,11 @@ class Batch extends AbstractBatchService /** * batch list method * - * @param array{ - * ID?: int, + * @param array { + * ID?: int * - * @param array{ - * ID?: int, + * @param array { + * ID?: int * } $filter * @param array $select = ['ID','CATALOG_ID','PRICE','CURRENCY_ID','NAME','CODE','DESCRIPTION','DESCRIPTION_TYPE','ACTIVE','SECTION_ID','SORT','VAT_ID','VAT_INCLUDED','MEASURE','XML_ID','PREVIEW_PICTURE','DETAIL_PICTURE','DATE_CREATE','TIMESTAMP_X','MODIFIED_BY','CREATED_BY'] * @param int|null $limit From 4fad86dd073b3b709440af215c0d5f96bfccc89e Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 26 Nov 2021 23:21:04 +0300 Subject: [PATCH 242/647] fix phpstan errors on level 2 Signed-off-by: mesilov --- phpstan.neon.dist | 2 +- src/Services/CRM/Product/Service/Batch.php | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 8fe7e307..fdcb58e0 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,5 +1,5 @@ parameters: - level: 1 + level: 2 paths: - src/ # - tests/ diff --git a/src/Services/CRM/Product/Service/Batch.php b/src/Services/CRM/Product/Service/Batch.php index 2539ba79..ee553c60 100644 --- a/src/Services/CRM/Product/Service/Batch.php +++ b/src/Services/CRM/Product/Service/Batch.php @@ -20,10 +20,11 @@ class Batch extends AbstractBatchService /** * batch list method * - * @param array { + * @param array{ * ID?: int + * } $order * - * @param array { + * @param array{ * ID?: int * } $filter * @param array $select = ['ID','CATALOG_ID','PRICE','CURRENCY_ID','NAME','CODE','DESCRIPTION','DESCRIPTION_TYPE','ACTIVE','SECTION_ID','SORT','VAT_ID','VAT_INCLUDED','MEASURE','XML_ID','PREVIEW_PICTURE','DETAIL_PICTURE','DATE_CREATE','TIMESTAMP_X','MODIFIED_BY','CREATED_BY'] From b037f167d40904b831cde7e8a528d5e69b391d2b Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 26 Nov 2021 23:25:50 +0300 Subject: [PATCH 243/647] fix phpstan errors on level 3 Signed-off-by: mesilov --- phpstan.neon.dist | 2 +- src/Core/Credentials/AccessToken.php | 17 +++------ src/Core/Credentials/Credentials.php | 4 +-- src/Core/Response/DTO/RenewedAccessToken.php | 37 +++++--------------- src/Core/Response/DTO/Time.php | 32 ++++------------- 5 files changed, 22 insertions(+), 70 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index fdcb58e0..521f0ad4 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,5 +1,5 @@ parameters: - level: 2 + level: 3 paths: - src/ # - tests/ diff --git a/src/Core/Credentials/AccessToken.php b/src/Core/Credentials/AccessToken.php index 6600bcda..794d13a3 100644 --- a/src/Core/Credentials/AccessToken.php +++ b/src/Core/Credentials/AccessToken.php @@ -11,18 +11,9 @@ */ class AccessToken { - /** - * @var string - */ - protected $accessToken; - /** - * @var string - */ - protected $refreshToken; - /** - * @var int - */ - protected $expires; + protected string $accessToken; + protected string $refreshToken; + protected int $expires; /** * AccessToken constructor. @@ -73,7 +64,7 @@ public function hasExpired(): bool /** * @param array $request * - * @return static + * @return self */ public static function initFromArray(array $request): self { diff --git a/src/Core/Credentials/Credentials.php b/src/Core/Credentials/Credentials.php index ed868228..8c8932d2 100644 --- a/src/Core/Credentials/Credentials.php +++ b/src/Core/Credentials/Credentials.php @@ -93,7 +93,7 @@ public function getAccessToken(): ?AccessToken /** * @param WebhookUrl $webhookUrl * - * @return static + * @return self */ public static function createForWebHook(WebhookUrl $webhookUrl): self { @@ -110,7 +110,7 @@ public static function createForWebHook(WebhookUrl $webhookUrl): self * @param ApplicationProfile $applicationProfile * @param string $domainUrl * - * @return static + * @return self */ public static function createForOAuth(AccessToken $accessToken, ApplicationProfile $applicationProfile, string $domainUrl): self { diff --git a/src/Core/Response/DTO/RenewedAccessToken.php b/src/Core/Response/DTO/RenewedAccessToken.php index 6623fd2e..a338c17a 100644 --- a/src/Core/Response/DTO/RenewedAccessToken.php +++ b/src/Core/Response/DTO/RenewedAccessToken.php @@ -14,34 +14,13 @@ */ class RenewedAccessToken { - /** - * @var AccessToken - */ - private $accessToken; - /** - * @var Scope - */ - private $scope; - /** - * @var string - */ - private $memberId; - /** - * @var string - */ - private $clientEndpoint; - /** - * @var string - */ - private $serverEndpoint; - /** - * @var string - */ - private $applicationStatus; - /** - * @var string - */ - private $domain; + private AccessToken $accessToken; + private Scope $scope; + private string $memberId; + private string $clientEndpoint; + private string $serverEndpoint; + private string $applicationStatus; + private string $domain; /** * RenewedAccessToken constructor. @@ -131,7 +110,7 @@ public function getDomain(): string /** * @param array $response * - * @return static + * @return self * @throws \Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException */ public static function initFromArray(array $response): self diff --git a/src/Core/Response/DTO/Time.php b/src/Core/Response/DTO/Time.php index 8bd32305..3d41ec45 100644 --- a/src/Core/Response/DTO/Time.php +++ b/src/Core/Response/DTO/Time.php @@ -11,30 +11,12 @@ */ class Time { - /** - * @var float - */ - protected $start; - /** - * @var float - */ - protected $finish; - /** - * @var float - */ - protected $duration; - /** - * @var float - */ - protected $processing; - /** - * @var \DateTimeImmutable - */ - protected $dateStart; - /** - * @var \DateTimeImmutable - */ - protected $dateFinish; + protected float $start; + protected float $finish; + protected float $duration; + protected float $processing; + protected \DateTimeImmutable $dateStart; + protected \DateTimeImmutable $dateFinish; /** * Time constructor. @@ -113,7 +95,7 @@ public function getDateFinish(): \DateTimeImmutable /** * @param array $response * - * @return static + * @return self * @throws \Exception */ public static function initFromResponse(array $response): self From 9b7e8160a49e44723015cc66a6095629339075d7 Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 26 Nov 2021 23:41:48 +0300 Subject: [PATCH 244/647] fix phpstan errors on level 5 Signed-off-by: mesilov --- phpstan.neon.dist | 2 +- src/Core/Batch.php | 2 +- src/Core/Credentials/Scope.php | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 521f0ad4..6856bc7f 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,5 +1,5 @@ parameters: - level: 3 + level: 5 paths: - src/ # - tests/ diff --git a/src/Core/Batch.php b/src/Core/Batch.php index b53f7216..8b31fa14 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -476,7 +476,7 @@ public function getTraversable(bool $isHaltOnError): Generator } $nextItem = null; - if ($resultNextItems !== null && array_key_exists($singleQueryKey, $resultNextItems) && count($resultNextItems) > 0) { + if ($resultNextItems !== null && array_key_exists($singleQueryKey, $resultNextItems)) { $nextItem = $resultNextItems[$singleQueryKey]; } diff --git a/src/Core/Credentials/Scope.php b/src/Core/Credentials/Scope.php index a7375659..f9b5d10f 100644 --- a/src/Core/Credentials/Scope.php +++ b/src/Core/Credentials/Scope.php @@ -71,8 +71,7 @@ class Scope */ public function __construct(array $scope = []) { - $scope = array_map('strtolower', $scope); - array_unique($scope); + $scope = array_unique(array_map('strtolower', $scope)); foreach ($scope as $item) { if (!in_array($item, $this->availableScope, true)) { throw new UnknownScopeCodeException(sprintf('unknown application scope code - %s', $item)); From 7ca1ff5ab2233d282b15015f7afaa915daf6a433 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 27 Nov 2021 00:23:48 +0300 Subject: [PATCH 245/647] fix errors on test suites Signed-off-by: mesilov --- .github/workflows/phpunit.yml | 7 ++---- .gitignore | 3 ++- composer.json | 13 +++++++----- phpunit.xml.dist | 7 ++++-- tests/Integration/Fabric.php | 40 +++++++++++++++++++++++++++++++++++ tests/bootstrap.php | 20 +++++++++++++++++- 6 files changed, 76 insertions(+), 14 deletions(-) create mode 100644 tests/Integration/Fabric.php diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index c0040183..f99825a2 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -33,8 +33,5 @@ jobs: run: | composer update ${{ env.COMPOSER_FLAGS }} - - name: "Run tests" - run: "composer exec phpunit -- --verbose" - - - name: Run test suite - run: composer run-script unit-tests \ No newline at end of file + - name: "run unit tests" + run: "composer phpunit-run-unit-tests" \ No newline at end of file diff --git a/.gitignore b/.gitignore index 0cff48d7..7c3db918 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ composer.lock .phpunit.result.cache tools/.env.local tools/logs -examples/logs \ No newline at end of file +examples/logs +.env.local \ No newline at end of file diff --git a/composer.json b/composer.json index 458fb99e..ad914b21 100644 --- a/composer.json +++ b/composer.json @@ -29,9 +29,9 @@ }, "require-dev": { "monolog/monolog": "2.1.*", - "symfony/console": "5.2.*", - "symfony/dotenv": "5.2.*", - "symfony/debug-bundle": "5.2.*", + "symfony/console": "5.3.*", + "symfony/dotenv": "5.3.*", + "symfony/debug-bundle": "5.3.*", "phpstan/phpstan": "1.1.*", "phpunit/phpunit": "9.5.*", "roave/security-advisories": "dev-master" @@ -48,8 +48,11 @@ } }, "scripts": { - "unit-tests": [ - "phpunit --colors=always --verbose" + "phpunit-run-unit-tests": [ + "phpunit --testsuite unit_tests" + ], + "phpunit-run-integration-tests": [ + "phpunit --testsuite integration_tests" ], "phpstan-analyse": [ "vendor/bin/phpstan analyse" diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 3d33e504..a3e33d9d 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -3,7 +3,7 @@ xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd" backupGlobals="false" colors="true" - bootstrap="vendor/autoload.php" + bootstrap="tests/bootstrap.php" failOnRisky="true" failOnWarning="true"> @@ -15,8 +15,11 @@ - + ./tests/Unit + + ./tests/Integration + diff --git a/tests/Integration/Fabric.php b/tests/Integration/Fabric.php new file mode 100644 index 00000000..b808b82f --- /dev/null +++ b/tests/Integration/Fabric.php @@ -0,0 +1,40 @@ +pushHandler(new StreamHandler(STDOUT, (int)$_ENV['INTEGRATION_TEST_LOG_LEVEL'])); + $log->pushProcessor(new \Monolog\Processor\MemoryUsageProcessor(true, true)); + $log->pushProcessor(new \Monolog\Processor\IntrospectionProcessor()); + $log->debug('=============================================================='); + + $core = (new CoreBuilder()) + ->withLogger($log) + ->withWebhookUrl($_ENV['BITRIX24_WEBHOOK']) + ->build(); + $batch = new Batch($core, $log); + + return new ServiceBuilder($core, $batch, $log); + } +} \ No newline at end of file diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 0588c285..e1d57556 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -2,4 +2,22 @@ declare(strict_types=1); -require_once \dirname(__DIR__) . '/vendor/autoload.php'; +use Symfony\Component\Console\Input\ArgvInput; +use Symfony\Component\Dotenv\Dotenv; + +require_once dirname(__DIR__) . '/vendor/autoload.php'; + +if (!class_exists(Dotenv::class)) { + throw new LogicException('You need to add "symfony/dotenv" as Composer dependencies.'); +} + +$input = new ArgvInput(); +if (null !== $env = $input->getParameterOption(['--env', '-e'], null, true)) { + putenv('APP_ENV=' . $_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = $env); +} + +if ($input->hasParameterOption('--no-debug', true)) { + putenv('APP_DEBUG=' . $_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = '0'); +} + +(new Dotenv())->bootEnv(dirname(__DIR__) .'/tests/.env.local'); \ No newline at end of file From dd575fa26100f2ed5aee490d396cd08b9c1a3a33 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 27 Nov 2021 00:34:33 +0300 Subject: [PATCH 246/647] fix errors on test suites Signed-off-by: mesilov --- tests/.env | 21 +++++++++++++++++++++ tests/bootstrap.php | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 tests/.env diff --git a/tests/.env b/tests/.env new file mode 100644 index 00000000..fb14da23 --- /dev/null +++ b/tests/.env @@ -0,0 +1,21 @@ +# In all environments, the following files are loaded if they exist, +# the latter taking precedence over the former: +# +# * .env contains default values for the environment variables needed by the app +# * .env.local uncommitted file with local overrides +# * .env.$APP_ENV committed environment-specific defaults +# * .env.$APP_ENV.local uncommitted environment-specific overrides +# +# Real environment variables win over .env files. +# +# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES. +# +# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2). +# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration + +# For run integration tests you must create incoming webhook for YOUR bitrix24 portal and create .env.local file with same settings + +APP_ENV=dev +BITRIX24_WEBHOOK= +# monolog log level +INTEGRATION_TEST_LOG_LEVEL= \ No newline at end of file diff --git a/tests/bootstrap.php b/tests/bootstrap.php index e1d57556..0e854a6b 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -20,4 +20,4 @@ putenv('APP_DEBUG=' . $_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = '0'); } -(new Dotenv())->bootEnv(dirname(__DIR__) .'/tests/.env.local'); \ No newline at end of file +(new Dotenv())->loadEnv(dirname(__DIR__).'/tests/.env'); \ No newline at end of file From ca3aec35fbd32e2d834c01eaf4ff89115bcaaa47 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 27 Nov 2021 01:33:02 +0300 Subject: [PATCH 247/647] update documentation Signed-off-by: mesilov --- README.md | 130 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 93 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 8d5f45a9..fc42448b 100644 --- a/README.md +++ b/README.md @@ -3,49 +3,62 @@ bitrix24-php-sdk [![Build Status](https://travis-ci.org/mesilov/bitrix24-php-sdk [![License](https://poser.pugx.org/mesilov/bitrix24-php-sdk/license.svg)](https://packagist.org/packages/mesilov/bitrix24-php-sdk) [![Total Downloads](https://poser.pugx.org/mesilov/bitrix24-php-sdk/downloads.svg)](https://packagist.org/packages/mesilov/bitrix24-php-sdk) A powerful PHP library for the Bitrix24 REST API +### BITRIX24-PHP-SDK 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)
+- [Russian](/docs/RU/documentation.md) +- [English](/docs/EN/documentation.md) -### SDK 2.0 core features +### BITRIX24-PHP-SDK ✨FEATURES✨ -Bitrix24 auth features +Support both auth modes: -- ~~work with auth tokens~~ -- ~~work with incoming webhooks~~ +- [x] work with auth tokens for Bitrix24 applications in marketplace +- [x] work with incoming webhooks for simple integration projects for current portal -add low-level tools to devs: +Low-level tools to devs: -- ~~2.1 events (token expired, domain url changed)~~ -- 2.2 rate-limiter - wait for symfony/symfony#37471 -- 2.3 RetryHttpClient - symfony/symfony#38182 +- Domain core events: + - [x] Access Token expired + - [ ] Bitrix24 portal domain url changed +- [ ] Rate-limit strategy +- [ ] Retry strategy for safe methods API - level features -- ~~3.1 auto renew access tokens~~ -- 3.2 batch queries (work in progress) -- ~~3.2.1 read~~ -- ~~3.2.2 write~~ -- 3.2.3 read + write -- 3.2.4 read without count flag -- 3.3 list queries with «start=-1» support -- 3.4 offline queues -- 3.5 add change domain URL support - -Core DTO - -- ~~Response~~ -- ~~Scope~~ -- ~~Time~~ -- ~~OAuthToken~~ -- ~~ApplicationProfile~~ -- ~~Pagination~~ - -### SDK Documentation - -- [Russian](/docs/RU/documentation.md) -- [English](/docs/EN/documentation.md) +- [x] Auto renew access tokens +- [ ] List queries with «start=-1» support +- [ ] offline queues + +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 + +### Development principles + +- Good developer experience + - auto-completion of methods at the IDE + - typed method call signatures + - typed results of method calls + - helpers for typical operations +- Good documentation + - documentation on the operation of a specific method containing a link to the official documentation + - documentation for working with the SDK +- Performance first: + - minimal impact on client code + - ability to work with large amounts of data with constant memory consumption + - efficient operation of the API using butch requests +- Modern technology stack + - based on [Symfony HttpClient](https://symfony.com/doc/current/http_client.html) + - actual PHP versions language features +- Reliable: + - test coverage: unit, integration, contract + - typical examples typical for different modes of operation and they are optimized for memory \ performance ### Architecture @@ -94,11 +107,46 @@ Core DTO Add `"mesilov/bitrix24-php-sdk": "2.x"` to `composer.json` of your application. Or clone repo to your project. ### Tests +Tests locate in folder `tests` and we have two test types + +#### 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 +``` + +#### Integration tests +**Slow** tests with full lifecycle with your **test** Bitrix24 portal via webhook. + +❗️Do not run integration tests with production portals ❗️ + +For run integration test you must: +1. Create [new Bitrix24 portal](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 +7. Create file `/tests/.env.local` with same settings, see comments in `/tests/.env` file. +```yaml +APP_ENV=dev +BITRIX24_WEBHOOK=https:// your portal webhook url +INTEGRATION_TEST_LOG_LEVEL=500 +``` +8. call in command line + +```shell +composer composer phpunit-run-integration-tests +``` -SDK test locate in folder `tests` and we have two test types +#### PHP Static Analysis Tool – phpstan +Call in command line +```shell + composer phpstan-analyse +``` -- Unit: **fast**, in-memory tests without a network I\O -- Integration: **slow** tests with full lifecycle with test Bitrix24 portal via webhook ### Submitting bugs and feature requests @@ -119,6 +167,14 @@ email: ### Sponsors +### 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) + ## Русский ### Принципы по которым ведётся разработка From 6a4eabfe9794e5f89150d20f205e0b9365b93bad Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 27 Nov 2021 01:48:21 +0300 Subject: [PATCH 248/647] add method count by filter Signed-off-by: mesilov --- CHANGELOG.md | 2 +- src/Services/CRM/Deal/Service/Deal.php | 50 +++++++++++++++++++ src/Services/CRM/Product/Service/Product.php | 36 +++++++++++++ .../Services/CRM/Deal/Service/DealTest.php | 25 ++++++++++ .../CRM/Products/Service/ProductsTest.php | 24 +++++++++ 5 files changed, 136 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b7dbebe9..cc5d3991 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ### Added -* add method `countByFilter` for all services, see +* add method `countByFilter` for all related services, see issue [Добавить для всех сущностей метод подсчёта количества элементов по фильтру #228](https://github.com/mesilov/bitrix24-php-sdk/issues/228) ### Removed diff --git a/src/Services/CRM/Deal/Service/Deal.php b/src/Services/CRM/Deal/Service/Deal.php index c8289157..fac6432e 100644 --- a/src/Services/CRM/Deal/Service/Deal.php +++ b/src/Services/CRM/Deal/Service/Deal.php @@ -249,4 +249,54 @@ public function update(int $id, array $fields, array $params): UpdatedItemResult ) ); } + + /** + * Count deals by filter + * + * @param array{ + * ID?: int, + * TITLE?: string, + * TYPE_ID?: string, + * CATEGORY_ID?: string, + * STAGE_ID?: string, + * STAGE_SEMANTIC_ID?: string, + * IS_NEW?: string, + * IS_RECURRING?: string, + * PROBABILITY?: string, + * CURRENCY_ID?: string, + * OPPORTUNITY?: string, + * IS_MANUAL_OPPORTUNITY?: string, + * TAX_VALUE?: string, + * LEAD_ID?: string, + * COMPANY_ID?: string, + * CONTACT_ID?: string, + * QUOTE_ID?: string, + * BEGINDATE?: string, + * CLOSEDATE?: string, + * OPENED?: string, + * CLOSED?: string, + * COMMENTS?: string, + * ADDITIONAL_INFO?: string, + * LOCATION_ID?: string, + * IS_RETURN_CUSTOMER?: string, + * IS_REPEATED_APPROACH?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string + * } $filter + * + * @return int + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function countByFilter(array $filter = []): int + { + return $this->list([], $filter, ['ID'], 1)->getCoreResponse()->getResponseData()->getPagination()->getTotal(); + } } \ No newline at end of file diff --git a/src/Services/CRM/Product/Service/Product.php b/src/Services/CRM/Product/Service/Product.php index 9a725eda..1a94f095 100644 --- a/src/Services/CRM/Product/Service/Product.php +++ b/src/Services/CRM/Product/Service/Product.php @@ -211,4 +211,40 @@ public function update(int $id, array $fields): UpdatedItemResult ) ); } + + /** + * Count products by filter + * + * @param array{ + * ID?: int, + * CATALOG_ID?: int, + * PRICE?: string, + * CURRENCY_ID?: string, + * NAME?: string, + * CODE?: string, + * DESCRIPTION?: string, + * DESCRIPTION_TYPE?: string, + * ACTIVE?: string, + * SECTION_ID?: int, + * SORT?: int, + * VAT_ID?: int, + * VAT_INCLUDED?: string, + * MEASURE?: int, + * XML_ID?: string, + * PREVIEW_PICTURE?: string, + * DETAIL_PICTURE?: string, + * DATE_CREATE?: string, + * TIMESTAMP_X?: string, + * MODIFIED_BY?: int, + * CREATED_BY?: int + * } $filter + * + * @return int + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function countByFilter(array $filter = []): int + { + return $this->list([], $filter, ['ID'], 1)->getCoreResponse()->getResponseData()->getPagination()->getTotal(); + } } \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Deal/Service/DealTest.php b/tests/Integration/Services/CRM/Deal/Service/DealTest.php index 356183fa..fc9b853c 100644 --- a/tests/Integration/Services/CRM/Deal/Service/DealTest.php +++ b/tests/Integration/Services/CRM/Deal/Service/DealTest.php @@ -115,6 +115,31 @@ public function testBatchAdd(): void self::assertEquals(count($deals), $cnt); } + /** + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\Deal::countByFilter + */ + public function testCountByFilter(): void + { + $before = $this->dealService->countByFilter(); + + $newDealsCount = 60; + $deals = []; + for ($i = 1; $i <= $newDealsCount; $i++) { + $deals[] = ['TITLE' => 'TITLE-' . $i]; + } + $cnt = 0; + foreach ($this->dealService->batch->add($deals) as $item) { + $cnt++; + } + self::assertEquals(count($deals), $cnt); + + $after = $this->dealService->countByFilter(); + + $this->assertEquals($before + $newDealsCount, $after); + } + public function setUp(): void { $this->dealService = Fabric::getServiceBuilder()->getCRMScope()->deal(); diff --git a/tests/Integration/Services/CRM/Products/Service/ProductsTest.php b/tests/Integration/Services/CRM/Products/Service/ProductsTest.php index b58f0ea4..0e9223ba 100644 --- a/tests/Integration/Services/CRM/Products/Service/ProductsTest.php +++ b/tests/Integration/Services/CRM/Products/Service/ProductsTest.php @@ -123,6 +123,30 @@ public function testBatchAdd(): void self::assertEquals(count($products), $cnt); } + /** + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @covers \Bitrix24\SDK\Services\CRM\Product\Service\Product::countByFilter + */ + public function testCountByFilter(): void + { + $productsCountBefore = $this->productService->countByFilter(); + $newProductsCount = 60; + $products = []; + for ($i = 1; $i <= $newProductsCount; $i++) { + $products[] = ['NAME' => 'NAME-' . $i]; + } + $cnt = 0; + foreach ($this->productService->batch->add($products) as $item) { + $cnt++; + } + + self::assertEquals(count($products), $cnt); + + $productsCountAfter = $this->productService->countByFilter(); + $this->assertEquals($productsCountBefore + $newProductsCount, $productsCountAfter); + } + public function setUp(): void { $this->productService = Fabric::getServiceBuilder()->getCRMScope()->product(); From 6cee3f80102f166dee9bd3b26eeaa32bf029ebee Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 27 Nov 2021 23:36:21 +0300 Subject: [PATCH 249/647] update Scope.php Signed-off-by: mesilov --- src/Core/Credentials/Scope.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Core/Credentials/Scope.php b/src/Core/Credentials/Scope.php index f9b5d10f..3ddda1fa 100644 --- a/src/Core/Credentials/Scope.php +++ b/src/Core/Credentials/Scope.php @@ -16,11 +16,12 @@ class Scope /** * @var string[] */ - protected $availableScope = [ + protected array $availableScope = [ 'app', 'bizproc', 'calendar', 'call', + 'catalog', 'contact_center', 'crm', 'delivery', @@ -60,7 +61,7 @@ class Scope /** * @var array */ - protected $currentScope = []; + protected array $currentScope = []; /** * Scope constructor. From ac7738bb3224bda96e744f6e8cac0adbe3f96e45 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 28 Nov 2021 00:19:01 +0300 Subject: [PATCH 250/647] add userfield type Signed-off-by: mesilov --- CHANGELOG.md | 5 +- src/Services/CRM/CRMServiceBuilder.php | 15 ++++ .../Result/UserfieldTypeItemResult.php | 15 ++++ .../Userfield/Result/UserfieldTypesResult.php | 25 +++++++ .../CRM/Userfield/Service/Userfield.php | 73 +++++++++++++++++++ .../CRM/Userfield/Service/UserfieldTest.php | 63 ++++++++++++++++ 6 files changed, 194 insertions(+), 2 deletions(-) create mode 100644 src/Services/CRM/Userfield/Result/UserfieldTypeItemResult.php create mode 100644 src/Services/CRM/Userfield/Result/UserfieldTypesResult.php create mode 100644 src/Services/CRM/Userfield/Service/Userfield.php create mode 100644 tests/Integration/Services/CRM/Userfield/Service/UserfieldTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index cc5d3991..324069a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,13 @@ # bitrix24-php-sdk change log -## 2.0-alpha.5 – 26.11.2021 +## 2.0-alpha.5 – 28.11.2021 ### Added * add method `countByFilter` for all related services, see issue [Добавить для всех сущностей метод подсчёта количества элементов по фильтру #228](https://github.com/mesilov/bitrix24-php-sdk/issues/228) - +* add in scope «CRM» Userfield service and integration test + ### Removed * remove all `0.*` and `1.*` code from `2.*` branch diff --git a/src/Services/CRM/CRMServiceBuilder.php b/src/Services/CRM/CRMServiceBuilder.php index d8c2e0be..bde5dfd5 100644 --- a/src/Services/CRM/CRMServiceBuilder.php +++ b/src/Services/CRM/CRMServiceBuilder.php @@ -125,4 +125,19 @@ public function product(): Product\Service\Product return $this->serviceCache[__METHOD__]; } + + /** + * @return Userfield\Service\Userfield + */ + public function userfield(): Userfield\Service\Userfield + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Userfield\Service\Userfield( + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } } \ No newline at end of file diff --git a/src/Services/CRM/Userfield/Result/UserfieldTypeItemResult.php b/src/Services/CRM/Userfield/Result/UserfieldTypeItemResult.php new file mode 100644 index 00000000..57df56f0 --- /dev/null +++ b/src/Services/CRM/Userfield/Result/UserfieldTypeItemResult.php @@ -0,0 +1,15 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { + $res[] = new UserfieldTypeItemResult($item); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Userfield/Service/Userfield.php b/src/Services/CRM/Userfield/Service/Userfield.php new file mode 100644 index 00000000..8f436efb --- /dev/null +++ b/src/Services/CRM/Userfield/Service/Userfield.php @@ -0,0 +1,73 @@ +core->call('crm.userfield.types')); + } + + /** + * Returns field description for user fields. + * + * @link https://training.bitrix24.com/rest_help/crm/userfields/crm_userfield_fields.php + * @return \Bitrix24\SDK\Core\Result\FieldsResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function fields(): FieldsResult + { + return new FieldsResult($this->core->call('crm.userfield.fields')); + } + + /** + * Returns field description for "enumeration" user field type (list). + * + * @link https://training.bitrix24.com/rest_help/crm/userfields/crm_userfield_enumeration_fields.php + * @return \Bitrix24\SDK\Core\Result\FieldsResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function enumerationFields(): FieldsResult + { + return new FieldsResult($this->core->call('crm.userfield.enumeration.fields')); + } + + /** + * Returns settings field description for user field type. + * + * @link https://training.bitrix24.com/rest_help/crm/userfields/crm_userfield_settings_fields.php + * + * @param string $userfieldTypeId + * + * @return \Bitrix24\SDK\Core\Result\FieldsResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function settingsFields(string $userfieldTypeId): FieldsResult + { + return new FieldsResult( + $this->core->call('crm.userfield.settings.fields', [ + 'type' => $userfieldTypeId, + ]) + ); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Userfield/Service/UserfieldTest.php b/tests/Integration/Services/CRM/Userfield/Service/UserfieldTest.php new file mode 100644 index 00000000..f1397ca5 --- /dev/null +++ b/tests/Integration/Services/CRM/Userfield/Service/UserfieldTest.php @@ -0,0 +1,63 @@ +userfieldService->fields()->getFieldsDescription()); + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @covers \Bitrix24\SDK\Services\CRM\Userfield\Service\Userfield::enumerationFields + */ + public function testEnumerationFields(): void + { + self::assertIsArray($this->userfieldService->enumerationFields()->getFieldsDescription()); + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @covers \Bitrix24\SDK\Services\CRM\Userfield\Service\Userfield::settingsFields + */ + public function testSettingsFields(): void + { + foreach ($this->userfieldService->types()->getTypes() as $typeItem) { + self::assertIsArray($this->userfieldService->settingsFields($typeItem->ID)->getFieldsDescription()); + } + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @covers \Bitrix24\SDK\Services\CRM\Userfield\Service\Userfield::types + */ + public function testTypes(): void + { + $ufTypes = $this->userfieldService->types(); + $this->assertGreaterThan(10, $ufTypes->getTypes()); + } + + + public function setUp(): void + { + $this->userfieldService = Fabric::getServiceBuilder()->getCRMScope()->userfield(); + } +} \ No newline at end of file From 68aea3d57998f6ff1abcc3bed37fb124a42d3782 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 28 Nov 2021 02:21:58 +0300 Subject: [PATCH 251/647] add ContactUserfield service and test Signed-off-by: mesilov --- src/Services/CRM/CRMServiceBuilder.php | 15 ++ .../Result/ContactUserfieldItemResult.php | 11 + .../Contact/Result/ContactUserfieldResult.php | 18 ++ .../Result/ContactUserfieldsResult.php | 25 +++ .../CRM/Contact/Service/ContactUserfield.php | 202 ++++++++++++++++++ .../UserfieldNameIsTooLongException.php | 11 + .../Result/AbstractUserfieldItemResult.php | 32 +++ .../Contact/Service/ContactUserfieldTest.php | 142 ++++++++++++ 8 files changed, 456 insertions(+) create mode 100644 src/Services/CRM/Contact/Result/ContactUserfieldItemResult.php create mode 100644 src/Services/CRM/Contact/Result/ContactUserfieldResult.php create mode 100644 src/Services/CRM/Contact/Result/ContactUserfieldsResult.php create mode 100644 src/Services/CRM/Contact/Service/ContactUserfield.php create mode 100644 src/Services/CRM/Userfield/Exceptions/UserfieldNameIsTooLongException.php create mode 100644 src/Services/CRM/Userfield/Result/AbstractUserfieldItemResult.php create mode 100644 tests/Integration/Services/CRM/Contact/Service/ContactUserfieldTest.php diff --git a/src/Services/CRM/CRMServiceBuilder.php b/src/Services/CRM/CRMServiceBuilder.php index bde5dfd5..672fabf9 100644 --- a/src/Services/CRM/CRMServiceBuilder.php +++ b/src/Services/CRM/CRMServiceBuilder.php @@ -86,6 +86,21 @@ public function contact(): Contact\Service\Contact return $this->serviceCache[__METHOD__]; } + /** + * @return \Bitrix24\SDK\Services\CRM\Contact\Service\ContactUserfield + */ + public function contactUserfield(): Contact\Service\ContactUserfield + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Contact\Service\ContactUserfield( + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + /** * @return Deal\Service\DealProductRows */ diff --git a/src/Services/CRM/Contact/Result/ContactUserfieldItemResult.php b/src/Services/CRM/Contact/Result/ContactUserfieldItemResult.php new file mode 100644 index 00000000..06058da6 --- /dev/null +++ b/src/Services/CRM/Contact/Result/ContactUserfieldItemResult.php @@ -0,0 +1,11 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData()); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Contact/Result/ContactUserfieldsResult.php b/src/Services/CRM/Contact/Result/ContactUserfieldsResult.php new file mode 100644 index 00000000..fc583cb4 --- /dev/null +++ b/src/Services/CRM/Contact/Result/ContactUserfieldsResult.php @@ -0,0 +1,25 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { + $res[] = new ContactUserfieldItemResult($item); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Contact/Service/ContactUserfield.php b/src/Services/CRM/Contact/Service/ContactUserfield.php new file mode 100644 index 00000000..4b873c17 --- /dev/null +++ b/src/Services/CRM/Contact/Service/ContactUserfield.php @@ -0,0 +1,202 @@ +core->call( + 'crm.contact.userfield.list', + [ + 'order' => $order, + 'filter' => $filter, + ] + ) + ); + } + + /** + * Creates a new user field for contacts. + * + * System limitation for field name - 20 characters. + * Prefix UF_CRM_is always added to the user field name. + * As a result, the actual name length - 13 characters. + * + * @param array{ + * FIELD_NAME?: string, + * USER_TYPE_ID?: string, + * XML_ID?: string, + * SORT?: string, + * MULTIPLE?: string, + * MANDATORY?: string, + * SHOW_FILTER?: string, + * SHOW_IN_LIST?: string, + * EDIT_IN_LIST?: string, + * IS_SEARCHABLE?: string, + * EDIT_FORM_LABEL?: string, + * LIST_COLUMN_LABEL?: string, + * LIST_FILTER_LABEL?: string, + * ERROR_MESSAGE?: string, + * HELP_MESSAGE?: string, + * LIST?: string, + * SETTINGS?: string, + * } $userfieldItemFields + * + * @return \Bitrix24\SDK\Core\Result\AddedItemResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws UserfieldNameIsTooLongException + * @link https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_userfield_add.php + * + */ + public function add(array $userfieldItemFields): AddedItemResult + { + if (strlen($userfieldItemFields['FIELD_NAME']) > 13) { + throw new UserfieldNameIsTooLongException( + sprintf( + 'userfield name %s is too long %s, maximum length - 13 characters', + $userfieldItemFields['FIELD_NAME'], + strlen($userfieldItemFields['FIELD_NAME']) + ) + ); + } + + return new AddedItemResult( + $this->core->call( + 'crm.contact.userfield.add', + [ + 'fields' => $userfieldItemFields, + ] + ) + ); + } + + /** + * Deleted user field for contacts. + * + * @param int $userfieldId + * + * @return \Bitrix24\SDK\Core\Result\DeletedItemResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_userfield_delete.php + * + */ + public function delete(int $userfieldId): DeletedItemResult + { + return new DeletedItemResult( + $this->core->call( + 'crm.contact.userfield.delete', + [ + 'id' => $userfieldId, + ] + ) + ); + } + + /** + * Returns a user field for contacts by ID. + * + * @param int $contactUserfieldItemId + * + * @return \Bitrix24\SDK\Services\CRM\Contact\Result\ContactUserfieldResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_userfield_get.php + */ + public function get(int $contactUserfieldItemId): ContactUserfieldResult + { + return new ContactUserfieldResult( + $this->core->call( + 'crm.contact.userfield.get', + [ + 'id' => $contactUserfieldItemId, + ] + ) + ); + } + + /** + * Updates an existing user field for contacts. + * + * @param int $contactUserfieldItemId + * @param array $userfieldFieldsToUpdate + * + * @return \Bitrix24\SDK\Core\Result\UpdatedItemResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_userfield_update.php + */ + public function update(int $contactUserfieldItemId, array $userfieldFieldsToUpdate): UpdatedItemResult + { + return new UpdatedItemResult( + $this->core->call( + 'crm.contact.userfield.update', + [ + 'id' => $contactUserfieldItemId, + 'fields' => $userfieldFieldsToUpdate, + ] + ) + ); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Userfield/Exceptions/UserfieldNameIsTooLongException.php b/src/Services/CRM/Userfield/Exceptions/UserfieldNameIsTooLongException.php new file mode 100644 index 00000000..1c637c9e --- /dev/null +++ b/src/Services/CRM/Userfield/Exceptions/UserfieldNameIsTooLongException.php @@ -0,0 +1,11 @@ + [ + [ + 'FIELD_NAME' => sprintf('%s%s', substr((string)random_int(0, PHP_INT_MAX), 0, 3), time()), + 'EDIT_FORM_LABEL' => [ + 'ru' => 'тест uf тип string', + 'en' => 'test uf type string', + ], + 'LIST_COLUMN_LABEL' => [ + 'ru' => 'тест uf тип string', + 'en' => 'test uf type string', + ], + 'USER_TYPE_ID' => 'string', + 'XML_ID' => 'b24phpsdk_type_string', + 'SETTINGS' => [], + ], + ]; + + mt_srand(); + yield 'user type id integer' => [ + [ + 'FIELD_NAME' => sprintf('%s%s', substr((string)random_int(0, PHP_INT_MAX), 0, 3), time()), + 'EDIT_FORM_LABEL' => [ + 'ru' => 'тест uf тип integer', + 'en' => 'test uf type integer', + ], + 'LIST_COLUMN_LABEL' => [ + 'ru' => 'тест uf тип integer', + 'en' => 'test uf type integer', + ], + 'USER_TYPE_ID' => 'integer', + 'XML_ID' => 'b24phpsdk_type_integer', + 'SETTINGS' => [], + ], + ]; + } + + /** + * @param array $newUserFieldItem + * + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNameIsTooLongException + * @covers ContactUserfield::add + * @dataProvider systemUserfieldsDemoDataDataProvider + */ + public function testAdd(array $newUserFieldItem): void + { + self::assertGreaterThanOrEqual(1, $this->contactUserfieldService->add($newUserFieldItem)->getId()); + } + + /** + * @param array $newUserFieldItem + * + * @dataProvider systemUserfieldsDemoDataDataProvider + * @covers ContactUserfield::delete + */ + public function testDelete(array $newUserFieldItem): void + { + $newUserfieldId = $this->contactUserfieldService->add($newUserFieldItem)->getId(); + $this->assertTrue($this->contactUserfieldService->delete($newUserfieldId)->isSuccess()); + } + + /** + * @param array $newUserFieldItem + * + * @dataProvider systemUserfieldsDemoDataDataProvider + * @covers ContactUserfield::get + */ + public function testGet(array $newUserFieldItem): void + { + $newUserfieldId = $this->contactUserfieldService->add($newUserFieldItem)->getId(); + $ufField = $this->contactUserfieldService->get($newUserfieldId)->userfieldItem(); + $this->assertEquals($newUserfieldId, $ufField->ID); + $this->assertEquals($newUserFieldItem['USER_TYPE_ID'], $ufField->USER_TYPE_ID); + $this->assertEquals('UF_CRM_' . $newUserFieldItem['FIELD_NAME'], $ufField->FIELD_NAME); + $this->assertEquals($newUserFieldItem['XML_ID'], $ufField->XML_ID); + } + + /** + * @param array $newUserFieldItem + * + * @dataProvider systemUserfieldsDemoDataDataProvider + * @covers ContactUserfield::update + */ + public function testUpdate(array $newUserFieldItem): void + { + $newUserfieldId = $this->contactUserfieldService->add($newUserFieldItem)->getId(); + $ufFieldBefore = $this->contactUserfieldService->get($newUserfieldId)->userfieldItem(); + $this->assertEquals($newUserfieldId, $ufFieldBefore->ID); + $this->assertEquals($newUserFieldItem['USER_TYPE_ID'], $ufFieldBefore->USER_TYPE_ID); + $this->assertEquals('UF_CRM_' . $newUserFieldItem['FIELD_NAME'], $ufFieldBefore->FIELD_NAME); + $this->assertEquals($newUserFieldItem['XML_ID'], $ufFieldBefore->XML_ID); + + $this->assertTrue( + $this->contactUserfieldService->update( + $newUserfieldId, + [ + 'EDIT_FORM_LABEL' => $newUserFieldItem['EDIT_FORM_LABEL']['en'] . 'QQQ', + ] + )->isSuccess() + ); + + $ufFieldAfter = $this->contactUserfieldService->get($newUserfieldId)->userfieldItem(); + $this->assertEquals($ufFieldBefore->EDIT_FORM_LABEL['en'] . 'QQQ', $ufFieldAfter->EDIT_FORM_LABEL['en']); + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @covers \Bitrix24\SDK\Services\CRM\Contact\Service\ContactUserfield::list + */ + public function testList(): void + { + $ufFields = $this->contactUserfieldService->list([], []); + $this->assertGreaterThanOrEqual(0, count($ufFields->getUserfields())); + } + + public function setUp(): void + { + $this->contactUserfieldService = Fabric::getServiceBuilder()->getCRMScope()->contactUserfield(); + } +} \ No newline at end of file From 0c06ed55b79675c7012ab9e08e3c956dd078759d Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 28 Nov 2021 12:37:00 +0300 Subject: [PATCH 252/647] first contact userfields build Signed-off-by: mesilov --- CHANGELOG.md | 9 +- src/Core/Result/AbstractItem.php | 12 +- .../CRM/Common/Result/AbstractCrmItem.php | 65 +++++++++++ .../CRM/Contact/Result/ContactItemResult.php | 109 ++++++++++-------- src/Services/CRM/Contact/Service/Contact.php | 2 +- .../CRM/Deal/Result/DealItemResult.php | 4 +- .../CRM/Product/Result/ProductItemResult.php | 4 +- .../Exceptions/UserfieldNotFoundException.php | 11 ++ .../Result/AbstractUserfieldItemResult.php | 12 ++ .../Service/ContactUserfieldUseCaseTest.php | 92 +++++++++++++++ 10 files changed, 264 insertions(+), 56 deletions(-) create mode 100644 src/Services/CRM/Common/Result/AbstractCrmItem.php create mode 100644 src/Services/CRM/Userfield/Exceptions/UserfieldNotFoundException.php create mode 100644 tests/Integration/Services/CRM/Contact/Service/ContactUserfieldUseCaseTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 324069a6..cfe372e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,11 +7,18 @@ * add method `countByFilter` for all related services, see issue [Добавить для всех сущностей метод подсчёта количества элементов по фильтру #228](https://github.com/mesilov/bitrix24-php-sdk/issues/228) * add in scope «CRM» Userfield service and integration test - +* add in scope «CRM» ContactUserfield service and integration test +* add method getUserfieldByFieldName for `ContactItemResult` +* add exception `UserfieldNotFoundException` + ### Removed * remove all `0.*` and `1.*` code from `2.*` branch +### Changed + +* update type definition for `ContactItemResult`, now return types will be cast to real types: DateTimeInterface, int, boolean etc + ## 2.0-alpha.4 – 25.11.2021 ### Changed diff --git a/src/Core/Result/AbstractItem.php b/src/Core/Result/AbstractItem.php index 82b5cd81..ca18e485 100644 --- a/src/Core/Result/AbstractItem.php +++ b/src/Core/Result/AbstractItem.php @@ -13,7 +13,7 @@ */ abstract class AbstractItem implements \IteratorAggregate { - private array $data; + protected array $data; /** * AbstractItem constructor. @@ -75,4 +75,14 @@ public function getIterator() { return new \ArrayIterator($this->data); } + + /** + * @param string $key + * + * @return bool + */ + protected function isKeyExists(string $key): bool + { + return array_key_exists($key, $this->data); + } } \ No newline at end of file diff --git a/src/Services/CRM/Common/Result/AbstractCrmItem.php b/src/Services/CRM/Common/Result/AbstractCrmItem.php new file mode 100644 index 00000000..e238ed90 --- /dev/null +++ b/src/Services/CRM/Common/Result/AbstractCrmItem.php @@ -0,0 +1,65 @@ +data[$offset]; + case 'EXPORT': + case 'HAS_PHONE': + case 'HAS_EMAIL': + case 'HAS_IMOL': + case 'OPENED': + return $this->data[$offset] === 'Y'; + case 'DATE_CREATE': + case 'DATE_MODIFY': + case 'BIRTHDATE': + if ($this->data[$offset] !== '') { + return DateTimeImmutable::createFromFormat(DATE_ATOM, $this->data[$offset]); + } + + return null; + default: + return $this->data[$offset] ?? null; + } + } + + /** + * get userfield by field name + * + * @param string $fieldName + * + * @return mixed|null + * @throws \Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNotFoundException + */ + protected function getKeyWithUserfieldByFieldName(string $fieldName) + { + $fieldName = self::CRM_USERFIELD_PREFIX . $fieldName; + if (!$this->isKeyExists($fieldName)) { + throw new UserfieldNotFoundException(sprintf('crm userfield not found by field name %s', $fieldName)); + } + + return $this->$fieldName; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Contact/Result/ContactItemResult.php b/src/Services/CRM/Contact/Result/ContactItemResult.php index d2e50906..82293707 100644 --- a/src/Services/CRM/Contact/Result/ContactItemResult.php +++ b/src/Services/CRM/Contact/Result/ContactItemResult.php @@ -4,59 +4,70 @@ namespace Bitrix24\SDK\Services\CRM\Contact\Result; -use Bitrix24\SDK\Core\Result\AbstractItem; +use Bitrix24\SDK\Services\CRM\Common\Result\AbstractCrmItem; +use DateTimeInterface; /** * 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 string $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 string $EXPORT - * @property-read string $HAS_PHONE - * @property-read string $HAS_EMAIL - * @property-read string $HAS_IMOL - * @property-read string $ASSIGNED_BY_ID - * @property-read string $CREATED_BY_ID - * @property-read string $MODIFY_BY_ID - * @property-read string $DATE_CREATE - * @property-read string $DATE_MODIFY - * @property-read string $COMPANY_ID - * @property-read string $COMPANY_IDS - * @property-read string $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 string $PHONE - * @property-read string $EMAIL - * @property-read string $WEB - * @property-read string $IM + * @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|DateTimeInterface $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 int $ASSIGNED_BY_ID + * @property-read int $CREATED_BY_ID + * @property-read int $MODIFY_BY_ID + * @property-read DateTimeInterface $DATE_CREATE + * @property-read DateTimeInterface $DATE_MODIFY + * @property-read string $COMPANY_ID + * @property-read string $COMPANY_IDS + * @property-read string $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 string $PHONE + * @property-read string $EMAIL + * @property-read string $WEB + * @property-read string $IM */ -class ContactItemResult extends AbstractItem +class ContactItemResult extends AbstractCrmItem { + /** + * @param string $userfieldName + * + * @return mixed|null + * @throws \Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNotFoundException + */ + public function getUserfieldByFieldName(string $userfieldName) + { + return $this->getKeyWithUserfieldByFieldName($userfieldName); + } } \ No newline at end of file diff --git a/src/Services/CRM/Contact/Service/Contact.php b/src/Services/CRM/Contact/Service/Contact.php index b3a7e1bc..211d6b6f 100644 --- a/src/Services/CRM/Contact/Service/Contact.php +++ b/src/Services/CRM/Contact/Service/Contact.php @@ -360,7 +360,7 @@ public function list(array $order, array $filter, array $select, int $start): Co * @throws BaseException * @throws TransportException */ - public function update(int $contactId, array $fields, array $params): UpdatedItemResult + public function update(int $contactId, array $fields, array $params = []): UpdatedItemResult { return new UpdatedItemResult( $this->core->call( diff --git a/src/Services/CRM/Deal/Result/DealItemResult.php b/src/Services/CRM/Deal/Result/DealItemResult.php index 123ffa90..e0341648 100644 --- a/src/Services/CRM/Deal/Result/DealItemResult.php +++ b/src/Services/CRM/Deal/Result/DealItemResult.php @@ -4,7 +4,7 @@ namespace Bitrix24\SDK\Services\CRM\Deal\Result; -use Bitrix24\SDK\Core\Result\AbstractItem; +use Bitrix24\SDK\Services\CRM\Common\Result\AbstractCrmItem; /** * Class DealItemResult @@ -45,6 +45,6 @@ * @property-read string|null $UTM_CONTENT * @property-read string|null $UTM_TERM */ -class DealItemResult extends AbstractItem +class DealItemResult extends AbstractCrmItem { } \ No newline at end of file diff --git a/src/Services/CRM/Product/Result/ProductItemResult.php b/src/Services/CRM/Product/Result/ProductItemResult.php index 9e894646..9d81c9a1 100644 --- a/src/Services/CRM/Product/Result/ProductItemResult.php +++ b/src/Services/CRM/Product/Result/ProductItemResult.php @@ -4,7 +4,7 @@ namespace Bitrix24\SDK\Services\CRM\Product\Result; -use Bitrix24\SDK\Core\Result\AbstractItem; +use Bitrix24\SDK\Services\CRM\Common\Result\AbstractCrmItem; /** * Class ProductItemResult @@ -31,6 +31,6 @@ * @property-read int $MODIFIED_BY * @property-read int $CREATED_BY */ -class ProductItemResult extends AbstractItem +class ProductItemResult extends AbstractCrmItem { } \ No newline at end of file diff --git a/src/Services/CRM/Userfield/Exceptions/UserfieldNotFoundException.php b/src/Services/CRM/Userfield/Exceptions/UserfieldNotFoundException.php new file mode 100644 index 00000000..eb551e77 --- /dev/null +++ b/src/Services/CRM/Userfield/Exceptions/UserfieldNotFoundException.php @@ -0,0 +1,11 @@ +FIELD_NAME, self::CRM_USERFIELD_PREFIX_LENGTH); + } } \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Contact/Service/ContactUserfieldUseCaseTest.php b/tests/Integration/Services/CRM/Contact/Service/ContactUserfieldUseCaseTest.php new file mode 100644 index 00000000..0e0cfb53 --- /dev/null +++ b/tests/Integration/Services/CRM/Contact/Service/ContactUserfieldUseCaseTest.php @@ -0,0 +1,92 @@ +contactUserfieldService->get($this->contactUserfieldId)->userfieldItem(); + $ufOriginalFieldName = $ufMetadata->getOriginalFieldName(); + $ufFieldName = $ufMetadata->FIELD_NAME; + + // add contact with uf value + $fieldNameValue = 'test field value'; + $newContactId = $this->contactService->add( + [ + 'NAME' => 'test contact', + $ufFieldName => $fieldNameValue, + ] + )->getId(); + $contact = $this->contactService->get($newContactId)->contact(); + $this->assertEquals($fieldNameValue, $contact->getUserfieldByFieldName($ufOriginalFieldName)); + + // update contact userfield value + $newUfValue = 'test 2'; + $this->assertTrue( + $this->contactService->update( + $contact->ID, + [ + $ufFieldName => $newUfValue, + ] + )->isSuccess() + ); + $updatedContact = $this->contactService->get($contact->ID)->contact(); + $this->assertEquals($newUfValue, $updatedContact->getUserfieldByFieldName($ufOriginalFieldName)); + } + + /** + * @throws \Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNameIsTooLongException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function setUp(): void + { + $this->contactService = Fabric::getServiceBuilder()->getCRMScope()->contact(); + $this->contactUserfieldService = Fabric::getServiceBuilder()->getCRMScope()->contactUserfield(); + + $this->contactUserfieldId = $this->contactUserfieldService->add( + [ + 'FIELD_NAME' => sprintf('%s%s', substr((string)random_int(0, PHP_INT_MAX), 0, 3), time()), + 'EDIT_FORM_LABEL' => [ + 'ru' => 'тест uf тип string', + 'en' => 'test uf type string', + ], + 'LIST_COLUMN_LABEL' => [ + 'ru' => 'тест uf тип string', + 'en' => 'test uf type string', + ], + 'USER_TYPE_ID' => 'string', + 'XML_ID' => 'b24phpsdk_type_string', + 'SETTINGS' => [ + 'DEFAULT_VALUE' => 'hello world', + ], + ] + )->getId(); + } + + public function tearDown(): void + { + $this->contactUserfieldService->delete($this->contactUserfieldId); + } +} \ No newline at end of file From 88949f58e49034e554e802205049f93be9e29442 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 28 Nov 2021 21:31:41 +0300 Subject: [PATCH 253/647] first deal userfields build Signed-off-by: mesilov --- CHANGELOG.md | 6 +- src/Services/CRM/CRMServiceBuilder.php | 15 ++ .../CRM/Deal/Result/DealItemResult.php | 10 + .../Deal/Result/DealUserfieldItemResult.php | 12 + .../CRM/Deal/Result/DealUserfieldResult.php | 19 ++ .../CRM/Deal/Result/DealUserfieldsResult.php | 26 +++ src/Services/CRM/Deal/Service/Deal.php | 2 +- .../CRM/Deal/Service/DealUserfield.php | 205 ++++++++++++++++++ .../CRM/Deal/Service/DealUserfieldTest.php | 142 ++++++++++++ .../Deal/Service/DealUserfieldUseCaseTest.php | 92 ++++++++ 10 files changed, 527 insertions(+), 2 deletions(-) create mode 100644 src/Services/CRM/Deal/Result/DealUserfieldItemResult.php create mode 100644 src/Services/CRM/Deal/Result/DealUserfieldResult.php create mode 100644 src/Services/CRM/Deal/Result/DealUserfieldsResult.php create mode 100644 src/Services/CRM/Deal/Service/DealUserfield.php create mode 100644 tests/Integration/Services/CRM/Deal/Service/DealUserfieldTest.php create mode 100644 tests/Integration/Services/CRM/Deal/Service/DealUserfieldUseCaseTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index cfe372e0..a7836731 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,12 @@ * add method `countByFilter` for all related services, see issue [Добавить для всех сущностей метод подсчёта количества элементов по фильтру #228](https://github.com/mesilov/bitrix24-php-sdk/issues/228) * add in scope «CRM» Userfield service and integration test -* add in scope «CRM» ContactUserfield service and integration test +* add in scope «CRM» ContactUserfield service and integration test, see + issue [Добавить для всех сущностей метод подсчёта количества элементов по фильтру #231](https://github.com/mesilov/bitrix24-php-sdk/issues/231) * add method getUserfieldByFieldName for `ContactItemResult` +* add in scope «CRM» DealUserfield service and integration test, see + issue [Добавить для всех сущностей метод подсчёта количества элементов по фильтру #232](https://github.com/mesilov/bitrix24-php-sdk/issues/232) +* add method getUserfieldByFieldName for `DealItemResult` * add exception `UserfieldNotFoundException` ### Removed diff --git a/src/Services/CRM/CRMServiceBuilder.php b/src/Services/CRM/CRMServiceBuilder.php index 672fabf9..82b5040e 100644 --- a/src/Services/CRM/CRMServiceBuilder.php +++ b/src/Services/CRM/CRMServiceBuilder.php @@ -70,6 +70,21 @@ public function deal(): Deal\Service\Deal return $this->serviceCache[__METHOD__]; } + /** + * @return \Bitrix24\SDK\Services\CRM\Deal\Service\DealUserfield + */ + public function dealUserfield(): Deal\Service\DealUserfield + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Deal\Service\DealUserfield( + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + /** * @return Contact\Service\Contact */ diff --git a/src/Services/CRM/Deal/Result/DealItemResult.php b/src/Services/CRM/Deal/Result/DealItemResult.php index e0341648..0737bca9 100644 --- a/src/Services/CRM/Deal/Result/DealItemResult.php +++ b/src/Services/CRM/Deal/Result/DealItemResult.php @@ -47,4 +47,14 @@ */ class DealItemResult extends AbstractCrmItem { + /** + * @param string $userfieldName + * + * @return mixed|null + * @throws \Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNotFoundException + */ + public function getUserfieldByFieldName(string $userfieldName) + { + return $this->getKeyWithUserfieldByFieldName($userfieldName); + } } \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealUserfieldItemResult.php b/src/Services/CRM/Deal/Result/DealUserfieldItemResult.php new file mode 100644 index 00000000..7531eae9 --- /dev/null +++ b/src/Services/CRM/Deal/Result/DealUserfieldItemResult.php @@ -0,0 +1,12 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData()); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealUserfieldsResult.php b/src/Services/CRM/Deal/Result/DealUserfieldsResult.php new file mode 100644 index 00000000..af523d1a --- /dev/null +++ b/src/Services/CRM/Deal/Result/DealUserfieldsResult.php @@ -0,0 +1,26 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { + $res[] = new DealUserfieldItemResult($item); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Service/Deal.php b/src/Services/CRM/Deal/Service/Deal.php index fac6432e..5f37aa57 100644 --- a/src/Services/CRM/Deal/Service/Deal.php +++ b/src/Services/CRM/Deal/Service/Deal.php @@ -236,7 +236,7 @@ public function list(array $order, array $filter, array $select, int $startItem * @throws BaseException * @throws TransportException */ - public function update(int $id, array $fields, array $params): UpdatedItemResult + public function update(int $id, array $fields, array $params = []): UpdatedItemResult { return new UpdatedItemResult( $this->core->call( diff --git a/src/Services/CRM/Deal/Service/DealUserfield.php b/src/Services/CRM/Deal/Service/DealUserfield.php new file mode 100644 index 00000000..e250db76 --- /dev/null +++ b/src/Services/CRM/Deal/Service/DealUserfield.php @@ -0,0 +1,205 @@ +core->call( + 'crm.deal.userfield.list', + [ + 'order' => $order, + 'filter' => $filter, + ] + ) + ); + } + + /** + * Created new user field for deals. + * + * System limitation for field name - 20 characters. + * Prefix UF_CRM_is always added to the user field name. + * As a result, the actual name length - 13 characters. + * + * @param array{ + * FIELD_NAME?: string, + * USER_TYPE_ID?: string, + * XML_ID?: string, + * SORT?: string, + * MULTIPLE?: string, + * MANDATORY?: string, + * SHOW_FILTER?: string, + * SHOW_IN_LIST?: string, + * EDIT_IN_LIST?: string, + * IS_SEARCHABLE?: string, + * EDIT_FORM_LABEL?: string, + * LIST_COLUMN_LABEL?: string, + * LIST_FILTER_LABEL?: string, + * ERROR_MESSAGE?: string, + * HELP_MESSAGE?: string, + * LIST?: string, + * SETTINGS?: string, + * } $userfieldItemFields + * + * @return \Bitrix24\SDK\Core\Result\AddedItemResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws UserfieldNameIsTooLongException + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_userfield_add.php + * + */ + public function add(array $userfieldItemFields): AddedItemResult + { + if (strlen($userfieldItemFields['FIELD_NAME']) > 13) { + throw new UserfieldNameIsTooLongException( + sprintf( + 'userfield name %s is too long %s, maximum length - 13 characters', + $userfieldItemFields['FIELD_NAME'], + strlen($userfieldItemFields['FIELD_NAME']) + ) + ); + } + + return new AddedItemResult( + $this->core->call( + 'crm.deal.userfield.add', + [ + 'fields' => $userfieldItemFields, + ] + ) + ); + } + + /** + * Deleted userfield for deals + * + * @param int $userfieldId + * + * @return \Bitrix24\SDK\Core\Result\DeletedItemResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_userfield_delete.php + * + */ + public function delete(int $userfieldId): DeletedItemResult + { + return new DeletedItemResult( + $this->core->call( + 'crm.deal.userfield.delete', + [ + 'id' => $userfieldId, + ] + ) + ); + } + + /** + * Returns a userfield for deal by ID. + * + * @param int $userfieldItemId + * + * @return \Bitrix24\SDK\Services\CRM\Deal\Result\DealUserfieldResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_userfield_get.php + */ + public function get(int $userfieldItemId): DealUserfieldResult + { + return new DealUserfieldResult( + $this->core->call( + 'crm.deal.userfield.get', + [ + 'id' => $userfieldItemId, + ] + ) + ); + } + + /** + * Updates an existing user field for deals. + * + * @param int $userfieldItemId + * @param array $userfieldFieldsToUpdate + * + * @return \Bitrix24\SDK\Core\Result\UpdatedItemResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_userfield_update.php + */ + public function update(int $userfieldItemId, array $userfieldFieldsToUpdate): UpdatedItemResult + { + return new UpdatedItemResult( + $this->core->call( + 'crm.deal.userfield.update', + [ + 'id' => $userfieldItemId, + 'fields' => $userfieldFieldsToUpdate, + ] + ) + ); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Deal/Service/DealUserfieldTest.php b/tests/Integration/Services/CRM/Deal/Service/DealUserfieldTest.php new file mode 100644 index 00000000..3055e8bc --- /dev/null +++ b/tests/Integration/Services/CRM/Deal/Service/DealUserfieldTest.php @@ -0,0 +1,142 @@ + [ + [ + 'FIELD_NAME' => sprintf('%s%s', substr((string)random_int(0, PHP_INT_MAX), 0, 3), time()), + 'EDIT_FORM_LABEL' => [ + 'ru' => 'тест uf тип string', + 'en' => 'test uf type string', + ], + 'LIST_COLUMN_LABEL' => [ + 'ru' => 'тест uf тип string', + 'en' => 'test uf type string', + ], + 'USER_TYPE_ID' => 'string', + 'XML_ID' => 'b24phpsdk_type_string', + 'SETTINGS' => [], + ], + ]; + + mt_srand(); + yield 'user type id integer' => [ + [ + 'FIELD_NAME' => sprintf('%s%s', substr((string)random_int(0, PHP_INT_MAX), 0, 3), time()), + 'EDIT_FORM_LABEL' => [ + 'ru' => 'тест uf тип integer', + 'en' => 'test uf type integer', + ], + 'LIST_COLUMN_LABEL' => [ + 'ru' => 'тест uf тип integer', + 'en' => 'test uf type integer', + ], + 'USER_TYPE_ID' => 'integer', + 'XML_ID' => 'b24phpsdk_type_integer', + 'SETTINGS' => [], + ], + ]; + } + + /** + * @param array $newUserFieldItem + * + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNameIsTooLongException + * @covers ContactUserfield::add + * @dataProvider systemUserfieldsDemoDataDataProvider + */ + public function testAdd(array $newUserFieldItem): void + { + self::assertGreaterThanOrEqual(1, $this->userfieldService->add($newUserFieldItem)->getId()); + } + + /** + * @param array $newUserFieldItem + * + * @dataProvider systemUserfieldsDemoDataDataProvider + * @covers ContactUserfield::delete + */ + public function testDelete(array $newUserFieldItem): void + { + $newUserfieldId = $this->userfieldService->add($newUserFieldItem)->getId(); + $this->assertTrue($this->userfieldService->delete($newUserfieldId)->isSuccess()); + } + + /** + * @param array $newUserFieldItem + * + * @dataProvider systemUserfieldsDemoDataDataProvider + * @covers ContactUserfield::get + */ + public function testGet(array $newUserFieldItem): void + { + $newUserfieldId = $this->userfieldService->add($newUserFieldItem)->getId(); + $ufField = $this->userfieldService->get($newUserfieldId)->userfieldItem(); + $this->assertEquals($newUserfieldId, $ufField->ID); + $this->assertEquals($newUserFieldItem['USER_TYPE_ID'], $ufField->USER_TYPE_ID); + $this->assertEquals('UF_CRM_' . $newUserFieldItem['FIELD_NAME'], $ufField->FIELD_NAME); + $this->assertEquals($newUserFieldItem['XML_ID'], $ufField->XML_ID); + } + + /** + * @param array $newUserFieldItem + * + * @dataProvider systemUserfieldsDemoDataDataProvider + * @covers ContactUserfield::update + */ + public function testUpdate(array $newUserFieldItem): void + { + $newUserfieldId = $this->userfieldService->add($newUserFieldItem)->getId(); + $ufFieldBefore = $this->userfieldService->get($newUserfieldId)->userfieldItem(); + $this->assertEquals($newUserfieldId, $ufFieldBefore->ID); + $this->assertEquals($newUserFieldItem['USER_TYPE_ID'], $ufFieldBefore->USER_TYPE_ID); + $this->assertEquals('UF_CRM_' . $newUserFieldItem['FIELD_NAME'], $ufFieldBefore->FIELD_NAME); + $this->assertEquals($newUserFieldItem['XML_ID'], $ufFieldBefore->XML_ID); + + $this->assertTrue( + $this->userfieldService->update( + $newUserfieldId, + [ + 'EDIT_FORM_LABEL' => $newUserFieldItem['EDIT_FORM_LABEL']['en'] . 'QQQ', + ] + )->isSuccess() + ); + + $ufFieldAfter = $this->userfieldService->get($newUserfieldId)->userfieldItem(); + $this->assertEquals($ufFieldBefore->EDIT_FORM_LABEL['en'] . 'QQQ', $ufFieldAfter->EDIT_FORM_LABEL['en']); + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @covers \Bitrix24\SDK\Services\CRM\Contact\Service\ContactUserfield::list + */ + public function testList(): void + { + $ufFields = $this->userfieldService->list([], []); + $this->assertGreaterThanOrEqual(0, count($ufFields->getUserfields())); + } + + public function setUp(): void + { + $this->userfieldService = Fabric::getServiceBuilder()->getCRMScope()->dealUserfield(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Deal/Service/DealUserfieldUseCaseTest.php b/tests/Integration/Services/CRM/Deal/Service/DealUserfieldUseCaseTest.php new file mode 100644 index 00000000..88f9d1a1 --- /dev/null +++ b/tests/Integration/Services/CRM/Deal/Service/DealUserfieldUseCaseTest.php @@ -0,0 +1,92 @@ +dealUserfieldService->get($this->dealUserfieldId)->userfieldItem(); + $ufOriginalFieldName = $ufMetadata->getOriginalFieldName(); + $ufFieldName = $ufMetadata->FIELD_NAME; + + // add deal with uf value + $fieldNameValue = 'test field value'; + $newDealId = $this->dealService->add( + [ + 'TITLE' => 'test deal', + $ufFieldName => $fieldNameValue, + ] + )->getId(); + $deal = $this->dealService->get($newDealId)->deal(); + $this->assertEquals($fieldNameValue, $deal->getUserfieldByFieldName($ufOriginalFieldName)); + + // update deal userfield value + $newUfValue = 'test 2'; + $this->assertTrue( + $this->dealService->update( + $deal->ID, + [ + $ufFieldName => $newUfValue, + ] + )->isSuccess() + ); + $updatedDeal = $this->dealService->get($deal->ID)->deal(); + $this->assertEquals($newUfValue, $updatedDeal->getUserfieldByFieldName($ufOriginalFieldName)); + } + + /** + * @throws \Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNameIsTooLongException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function setUp(): void + { + $this->dealService = Fabric::getServiceBuilder()->getCRMScope()->deal(); + $this->dealUserfieldService = Fabric::getServiceBuilder()->getCRMScope()->dealUserfield(); + + $this->dealUserfieldId = $this->dealUserfieldService->add( + [ + 'FIELD_NAME' => sprintf('%s%s', substr((string)random_int(0, PHP_INT_MAX), 0, 3), time()), + 'EDIT_FORM_LABEL' => [ + 'ru' => 'тест uf тип string', + 'en' => 'test uf type string', + ], + 'LIST_COLUMN_LABEL' => [ + 'ru' => 'тест uf тип string', + 'en' => 'test uf type string', + ], + 'USER_TYPE_ID' => 'string', + 'XML_ID' => 'b24phpsdk_type_string', + 'SETTINGS' => [ + 'DEFAULT_VALUE' => 'hello world', + ], + ] + )->getId(); + } + + public function tearDown(): void + { + $this->dealUserfieldService->delete($this->dealUserfieldId); + } +} \ No newline at end of file From ea1ea619ab0fe8569e5dded143a81aa0261d7311 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 28 Nov 2021 22:53:23 +0300 Subject: [PATCH 254/647] add types for deal Signed-off-by: mesilov --- .../CRM/Common/Result/AbstractCrmItem.php | 30 +++++++- .../CRM/Deal/Result/DealItemResult.php | 71 ++++++++++--------- 2 files changed, 64 insertions(+), 37 deletions(-) diff --git a/src/Services/CRM/Common/Result/AbstractCrmItem.php b/src/Services/CRM/Common/Result/AbstractCrmItem.php index e238ed90..0737315f 100644 --- a/src/Services/CRM/Common/Result/AbstractCrmItem.php +++ b/src/Services/CRM/Common/Result/AbstractCrmItem.php @@ -19,22 +19,48 @@ class AbstractCrmItem extends AbstractItem */ public function __get($offset) { - //todo унести в отдельный класс и покрыть тестами + // todo унести в отдельный класс и покрыть тестами + // приведение полей к реальным типам данных для основных сущностей CRM switch ($offset) { case 'ID': case 'ASSIGNED_BY_ID': case 'CREATED_BY_ID': case 'MODIFY_BY_ID': - return (int)$this->data[$offset]; + // deal + case 'LEAD_ID': + case 'CONTACT_ID': + case 'QUOTE_ID': + if ($this->data[$offset] !== '' && $this->data[$offset] !== null) { + return (int)$this->data[$offset]; + } + + return null; + case 'COMPANY_ID': + if ($this->data[$offset] !== '' && $this->data[$offset] !== null && $this->data[$offset] !== '0') { + return (int)$this->data[$offset]; + } + + return null; + + // contact case 'EXPORT': case 'HAS_PHONE': case 'HAS_EMAIL': case 'HAS_IMOL': case 'OPENED': + // deal + case 'IS_MANUAL_OPPORTUNITY': + case 'CLOSED': + case 'IS_NEW': + case 'IS_RECURRING': + case 'IS_RETURN_CUSTOMER': + case 'IS_REPEATED_APPROACH': return $this->data[$offset] === 'Y'; case 'DATE_CREATE': case 'DATE_MODIFY': case 'BIRTHDATE': + case 'BEGINDATE': + case 'CLOSEDATE': if ($this->data[$offset] !== '') { return DateTimeImmutable::createFromFormat(DATE_ATOM, $this->data[$offset]); } diff --git a/src/Services/CRM/Deal/Result/DealItemResult.php b/src/Services/CRM/Deal/Result/DealItemResult.php index 0737bca9..a77faa40 100644 --- a/src/Services/CRM/Deal/Result/DealItemResult.php +++ b/src/Services/CRM/Deal/Result/DealItemResult.php @@ -5,45 +5,46 @@ namespace Bitrix24\SDK\Services\CRM\Deal\Result; use Bitrix24\SDK\Services\CRM\Common\Result\AbstractCrmItem; +use DateTimeInterface; /** * 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 string $IS_NEW - * @property-read string $IS_RECURRING - * @property-read string|null $PROBABILITY - * @property-read string $CURRENCY_ID - * @property-read string $OPPORTUNITY - * @property-read string $IS_MANUAL_OPPORTUNITY - * @property-read string $TAX_VALUE - * @property-read string $LEAD_ID - * @property-read string $COMPANY_ID - * @property-read string $CONTACT_ID - * @property-read string $QUOTE_ID - * @property-read string $BEGINDATE - * @property-read string $CLOSEDATE - * @property-read string $OPENED - * @property-read string $CLOSED - * @property-read string|null $COMMENTS - * @property-read string|null $ADDITIONAL_INFO - * @property-read string|null $LOCATION_ID - * @property-read string $IS_RETURN_CUSTOMER - * @property-read string $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 $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 */ class DealItemResult extends AbstractCrmItem { From cf40ef9f2c89daff37e88076c04db76da37d4b97 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 28 Nov 2021 22:55:19 +0300 Subject: [PATCH 255/647] update changelog Signed-off-by: mesilov --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7836731..8a0e0f6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,10 +8,10 @@ issue [Добавить для всех сущностей метод подсчёта количества элементов по фильтру #228](https://github.com/mesilov/bitrix24-php-sdk/issues/228) * add in scope «CRM» Userfield service and integration test * add in scope «CRM» ContactUserfield service and integration test, see - issue [Добавить для всех сущностей метод подсчёта количества элементов по фильтру #231](https://github.com/mesilov/bitrix24-php-sdk/issues/231) + issue [Добавить сервис по работе с юзерфилдами контакта #231](https://github.com/mesilov/bitrix24-php-sdk/issues/231) * add method getUserfieldByFieldName for `ContactItemResult` * add in scope «CRM» DealUserfield service and integration test, see - issue [Добавить для всех сущностей метод подсчёта количества элементов по фильтру #232](https://github.com/mesilov/bitrix24-php-sdk/issues/232) + issue [Добавить сервис по работе с юзерфилдами cделки #232](https://github.com/mesilov/bitrix24-php-sdk/issues/232) * add method getUserfieldByFieldName for `DealItemResult` * add exception `UserfieldNotFoundException` From fa5cd050a1e5eabe6c82ed9df38c5e83587daf96 Mon Sep 17 00:00:00 2001 From: MrDeff Date: Fri, 17 Dec 2021 11:56:25 +0700 Subject: [PATCH 256/647] set credentials from core builder fix example --- examples/core/oauth-examp.php | 2 +- src/Core/CoreBuilder.php | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/examples/core/oauth-examp.php b/examples/core/oauth-examp.php index 4f2225e1..1e9badd6 100644 --- a/examples/core/oauth-examp.php +++ b/examples/core/oauth-examp.php @@ -44,7 +44,7 @@ static function (\Bitrix24\SDK\Events\AuthTokenRenewedEvent $event) { } ); - $app = new \Bitrix24\SDK\Services\Main($apiClient, $ed, $log); + $app = (new \Bitrix24\SDK\Core\CoreBuilder())->withCredentials($credentials)->withApiClient($apiClient)->build(); $log->debug('================================'); diff --git a/src/Core/CoreBuilder.php b/src/Core/CoreBuilder.php index a56c7b08..d55e4109 100644 --- a/src/Core/CoreBuilder.php +++ b/src/Core/CoreBuilder.php @@ -50,6 +50,17 @@ public function __construct() $this->apiLevelErrorHandler = new ApiLevelErrorHandler($this->logger); } + /** + * @param Credentials $credentials + * + * @return $this + */ + public function withCredentials(Credentials $credentials): self + { + $this->credentials = $credentials; + return $this; + } + /** * @param string $webhookUrl * From 5e03f54183f4b932eb9d6d49cbe7363746154892 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 16 Jan 2022 00:43:53 +0300 Subject: [PATCH 257/647] add validation for webhookUrl Signed-off-by: mesilov --- src/Core/Credentials/WebhookUrl.php | 14 ++++--- .../Unit/Core/Credentials/WebhookUrlTest.php | 39 +++++++++++++++++++ 2 files changed, 47 insertions(+), 6 deletions(-) create mode 100644 tests/Unit/Core/Credentials/WebhookUrlTest.php diff --git a/src/Core/Credentials/WebhookUrl.php b/src/Core/Credentials/WebhookUrl.php index 780d9e5c..e33cabd0 100644 --- a/src/Core/Credentials/WebhookUrl.php +++ b/src/Core/Credentials/WebhookUrl.php @@ -4,6 +4,8 @@ namespace Bitrix24\SDK\Core\Credentials; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; + /** * Class WebhookUrl * @@ -11,18 +13,18 @@ */ class WebhookUrl { - /** - * @var string - */ - protected $url; + protected string $url; /** - * WebHookToken constructor. - * * @param string $webhookUrl + * + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException */ public function __construct(string $webhookUrl) { + if (filter_var($webhookUrl, FILTER_VALIDATE_URL) === false) { + throw new InvalidArgumentException(sprintf('webhook URL %s is invalid', $webhookUrl)); + } $this->url = $webhookUrl; } diff --git a/tests/Unit/Core/Credentials/WebhookUrlTest.php b/tests/Unit/Core/Credentials/WebhookUrlTest.php new file mode 100644 index 00000000..bc9f439b --- /dev/null +++ b/tests/Unit/Core/Credentials/WebhookUrlTest.php @@ -0,0 +1,39 @@ +assertTrue(true); + } + + /** + * @return void + * @testdox Test invalid webhook url + * @covers \Bitrix24\SDK\Core\Credentials\WebhookUrl + */ + public function testInvalidWebhookUrl(): void + { + $this->expectException(InvalidArgumentException::class); + $wh = new WebhookUrl('qqqq'); + } +} From 1afa9de8690fb313c7f203e33081949f9141c6d3 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 16 Jan 2022 01:00:45 +0300 Subject: [PATCH 258/647] fix demoDataGenerator Signed-off-by: mesilov --- .../CRM/Contacts/GenerateContactsCommand.php | 74 +++++++++++-------- 1 file changed, 45 insertions(+), 29 deletions(-) diff --git a/tools/DemoDataGenerators/CRM/Contacts/GenerateContactsCommand.php b/tools/DemoDataGenerators/CRM/Contacts/GenerateContactsCommand.php index baf04d77..5da48d7c 100644 --- a/tools/DemoDataGenerators/CRM/Contacts/GenerateContactsCommand.php +++ b/tools/DemoDataGenerators/CRM/Contacts/GenerateContactsCommand.php @@ -4,8 +4,11 @@ namespace Bitrix24\SDK\Tools\DemoDataGenerators\CRM\Contacts; +use Bitrix24\SDK\Core\Batch; +use Bitrix24\SDK\Core\CoreBuilder; use Bitrix24\SDK\Core\Exceptions\BaseException; -use Bitrix24\SDK\Core\Response\DTO\ResponseData; +use Bitrix24\SDK\Services\ServiceBuilder; +use InvalidArgumentException; use Psr\Log\LoggerInterface; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; @@ -69,6 +72,20 @@ protected function configure(): void ); } + /** + * @param \Symfony\Component\Console\Input\InputInterface $input + * @param \Symfony\Component\Console\Output\OutputInterface $output + * + * @return void + */ + protected function interact(InputInterface $input, OutputInterface $output): void + { + $b24Webhook = (string)$input->getOption(self::WEBHOOK_URL); + if ($b24Webhook === '') { + throw new InvalidArgumentException(sprintf('option %s not found, you must set this option', self::WEBHOOK_URL)); + } + } + /** * @param InputInterface $input * @param OutputInterface $output @@ -93,26 +110,27 @@ protected function execute(InputInterface $input, OutputInterface $output): int ); try { - $contacts = $this->generateContacts($contactsCount); - - $core = (new \Bitrix24\SDK\Core\CoreBuilder()) + $core = (new CoreBuilder()) ->withLogger($this->logger) ->withWebhookUrl($b24Webhook) ->build(); + $services = new ServiceBuilder( + $core, + new Batch($core, $this->logger), + $this->logger + ); - $countResult = $core->call('crm.contact.list'); - $output->writeln(sprintf('contacts total count: %s', $countResult->getResponseData()->getPagination()->getTotal())); + $output->writeln(sprintf('contacts total count: %s', $services->getCRMScope()->contact()->countByFilter())); - $batch = new \Bitrix24\SDK\Core\Batch($core, $this->logger); - foreach ($contacts as $cnt => $contact) { - $batch->addCommand('crm.contact.add', $contact); - } $io->section('start adding contacts…'); - $timeStart = microtime(true); - foreach ($batch->getTraversable(true) as $queryCnt => $queryResultData) { + foreach ( + $services->getCRMScope()->contact()->batch->add( + $this->generateContacts($contactsCount) + ) as $queryCnt => $addedItem + ) { /** - * @var $queryResultData ResponseData + * @var $queryResultData \Bitrix24\SDK\Core\Result\AddedItemBatchResult */ $io->writeln( [ @@ -121,7 +139,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int round(memory_get_peak_usage(true) / 1024 / 1024, 2), $queryCnt + 1, $contactsCount, - $queryResultData->getResult()->getResultData()[0] + $addedItem->getId() ), ] ); @@ -131,11 +149,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int $io->success('contacts added'); } catch (BaseException $exception) { $io = new SymfonyStyle($input, $output); - $io->caution('Bitrix24 error'); + $io->caution(sprintf('error message: %s', $exception->getMessage())); $io->text( - [ - sprintf('%s', $exception->getMessage()), - ] + $exception->getTraceAsString() ); } catch (\Throwable $exception) { $io = new SymfonyStyle($input, $output); @@ -148,10 +164,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int } $this->logger->debug('GenerateContactsCommand.finish'); - return 0; + return Command::SUCCESS; } /** + * Generate fake contacts + * * @param int $contactsCount * * @return array $contacts @@ -162,16 +180,14 @@ protected function generateContacts(int $contactsCount): array $contacts = []; for ($i = 0; $i < $contactsCount; $i++) { $contacts[] = [ - 'fields' => [ - 'NAME' => sprintf('name_%s', $i), - 'LAST_NAME' => sprintf('last_%s', $i), - 'SECOND_NAME' => sprintf('second_%s', $i), - 'PHONE' => [ - ['VALUE' => sprintf('+7978%s', random_int(1000000, 9999999)), 'VALUE_TYPE' => 'MOBILE'], - ], - 'EMAIL' => [ - ['VALUE' => sprintf('test-%s@gmail.com', random_int(1000000, 9999999)), 'VALUE_TYPE' => 'WORK'], - ], + 'NAME' => sprintf('name_%s', $i), + 'LAST_NAME' => sprintf('last_%s', $i), + 'SECOND_NAME' => sprintf('second_%s', $i), + 'PHONE' => [ + ['VALUE' => sprintf('+7978%s', random_int(1000000, 9999999)), 'VALUE_TYPE' => 'MOBILE'], + ], + 'EMAIL' => [ + ['VALUE' => sprintf('test-%s@gmail.com', random_int(1000000, 9999999)), 'VALUE_TYPE' => 'WORK'], ], ]; } From 17b02aba24cc6f6dda9e9a65df58ad98f51f2b4d Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 16 Jan 2022 01:03:00 +0300 Subject: [PATCH 259/647] bump Symfony components version to 5.4.* Signed-off-by: mesilov --- composer.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/composer.json b/composer.json index ad914b21..ee87d098 100644 --- a/composer.json +++ b/composer.json @@ -22,16 +22,16 @@ "ext-curl": "*", "psr/log": "1.1.3", "fig/http-message-util": "1.1.*", - "symfony/http-client": "5.3.*", - "symfony/http-client-contracts": "^2.4", - "symfony/event-dispatcher": "5.3.*", - "ramsey/uuid": "^4.0" + "symfony/http-client": "5.4.*", + "symfony/http-client-contracts": "^2.5", + "symfony/event-dispatcher": "5.4.*", + "ramsey/uuid": "^4.2.3" }, "require-dev": { "monolog/monolog": "2.1.*", - "symfony/console": "5.3.*", - "symfony/dotenv": "5.3.*", - "symfony/debug-bundle": "5.3.*", + "symfony/console": "5.4.*", + "symfony/dotenv": "5.4.*", + "symfony/debug-bundle": "5.4.*", "phpstan/phpstan": "1.1.*", "phpunit/phpunit": "9.5.*", "roave/security-advisories": "dev-master" From 655834a3fb0d89bc9ba18c25f4287fb8077e20ad Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 16 Jan 2022 16:09:59 +0300 Subject: [PATCH 260/647] add Batch::deleteEntityItems Signed-off-by: mesilov --- CHANGELOG.md | 17 +++- src/Core/Batch.php | 74 +++++++++++++---- src/Core/Contracts/BatchInterface.php | 20 ++++- src/Core/Core.php | 1 + tests/Integration/Core/BatchTest.php | 111 ++++++++++++++++++++++++++ tests/Integration/Fabric.php | 37 +++++++-- tests/Unit/Stubs/NullBatch.php | 25 +++++- 7 files changed, 258 insertions(+), 27 deletions(-) create mode 100644 tests/Integration/Core/BatchTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a0e0f6c..2ed93a21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # bitrix24-php-sdk change log +## 2.0-alpha.6 — 16.01.2021 + +### Added + +* add «fast» batch-query without counting elements in result + recordset [Добавить поддержку выгрузки большого количества данных без подсчёта элементов (-1](https://github.com/mesilov/bitrix24-php-sdk/issues/248) +* add method `Core\Batch::deleteEntityItems` for delete items in batch mode and integration test + +### Changed + +* switch `symfony/http-client` to `5.4.*` version requirement. +* switch `symfony/http-client-contracts` to `^2.5` version requirement. +* switch `symfony/event-dispatcher` to `5.4.*` version requirement. +* switch `ramsey/uuid` to `^4.2.3` version requirement. + ## 2.0-alpha.5 – 28.11.2021 ### Added @@ -11,7 +26,7 @@ issue [Добавить сервис по работе с юзерфилдами контакта #231](https://github.com/mesilov/bitrix24-php-sdk/issues/231) * add method getUserfieldByFieldName for `ContactItemResult` * add in scope «CRM» DealUserfield service and integration test, see - issue [Добавить сервис по работе с юзерфилдами cделки #232](https://github.com/mesilov/bitrix24-php-sdk/issues/232) + issue [Добавить сервис по работе с юзерфилдами cделки #232](https://github.com/mesilov/bitrix24-php-sdk/issues/232) * add method getUserfieldByFieldName for `DealItemResult` * add exception `UserfieldNotFoundException` diff --git a/src/Core/Batch.php b/src/Core/Batch.php index 8b31fa14..0e77af84 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -46,7 +46,7 @@ public function __construct(CoreInterface $core, LoggerInterface $log) /** * Clear api commands collection */ - public function clearCommands(): void + protected function clearCommands(): void { $this->log->debug( 'clearCommands.start', @@ -59,12 +59,12 @@ public function clearCommands(): void } /** - * add entity items with batch call + * Add entity items with batch call * * @param string $apiMethod * @param array $entityItems * - * @return Generator + * @return Generator|ResponseData[] * @throws BaseException */ public function addEntityItems(string $apiMethod, array $entityItems): Generator @@ -80,7 +80,7 @@ public function addEntityItems(string $apiMethod, array $entityItems): Generator try { $this->clearCommands(); foreach ($entityItems as $cnt => $item) { - $this->addCommand($apiMethod, $item); + $this->registerCommand($apiMethod, $item); } foreach ($this->getTraversable(true) as $cnt => $addedItemResult) { @@ -102,7 +102,50 @@ public function addEntityItems(string $apiMethod, array $entityItems): Generator } /** - * add api command to commands collection for batch calls + * Delete entity items with batch call + * + * @param string $apiMethod + * @param array $entityItemId + * + * @return Generator|ResponseData[] + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function deleteEntityItems(string $apiMethod, array $entityItemId): Generator + { + $this->log->debug( + 'deleteEntityItems.start', + [ + 'apiMethod' => $apiMethod, + 'entityItems' => $entityItemId, + ] + ); + + try { + $this->clearCommands(); + foreach ($entityItemId as $cnt => $itemId) { + $this->registerCommand($apiMethod, ['ID' => $itemId]); + } + + foreach ($this->getTraversable(true) as $cnt => $deletedItemResult) { + yield $cnt => $deletedItemResult; + } + } catch (\Throwable $exception) { + $errorMessage = sprintf('batch delete entity items: %s', $exception->getMessage()); + $this->log->error( + $errorMessage, + [ + 'trace' => $exception->getTrace(), + ] + ); + + throw new BaseException($errorMessage, $exception->getCode(), $exception); + } + + $this->log->debug('deleteEntityItems.finish'); + } + + /** + * Register api command to command collection for batch calls * * @param string $apiMethod * @param array $parameters @@ -111,14 +154,14 @@ public function addEntityItems(string $apiMethod, array $entityItems): Generator * * @throws \Exception */ - public function addCommand( + protected function registerCommand( string $apiMethod, array $parameters = [], ?string $commandName = null, callable $callback = null - ) { + ): void { $this->log->debug( - 'addCommand.start', + 'registerCommand.start', [ 'apiMethod' => $apiMethod, 'parameters' => $parameters, @@ -129,7 +172,7 @@ public function addCommand( $this->commands->attach(new Command($apiMethod, $parameters, $commandName)); $this->log->debug( - 'addCommand.finish', + 'registerCommand.finish', [ 'commandsCount' => $this->commands->count(), ] @@ -190,6 +233,7 @@ protected function getReverseOrder(array $order): array * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + * @throws \Exception */ public function getTraversableListWithoutCount( string $apiMethod, @@ -249,7 +293,7 @@ public function getTraversableListWithoutCount( //more than one page in results - register list commands for ($startId = $firstId; $startId <= $lastId; $startId += self::MAX_ELEMENTS_IN_PAGE) { - $this->addCommand( + $this->registerCommand( $apiMethod, [ 'order' => [], @@ -293,7 +337,7 @@ public function getTraversableListWithoutCount( } } else { // one page in results - $this->addCommand( + $this->registerCommand( $apiMethod, [ 'order' => $order, @@ -323,6 +367,7 @@ public function getTraversableListWithoutCount( * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + * @throws \Exception */ public function getTraversableList(string $apiMethod, array $order, array $filter, array $select, ?int $limit = null): Generator { @@ -363,7 +408,7 @@ public function getTraversableList(string $apiMethod, array $order, array $filte if ($total > self::MAX_ELEMENTS_IN_PAGE && $nextItem !== null) { //more than one page in results - register list commands for ($startItem = 0; $startItem <= $total; $startItem += $nextItem) { - $this->addCommand( + $this->registerCommand( $apiMethod, [ 'order' => $order, @@ -378,7 +423,7 @@ public function getTraversableList(string $apiMethod, array $order, array $filte } } else { // one page in results - $this->addCommand( + $this->registerCommand( $apiMethod, [ 'order' => $order, @@ -434,8 +479,9 @@ public function getTraversableList(string $apiMethod, array $order, array $filte * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + * @throws \Exception */ - public function getTraversable(bool $isHaltOnError): Generator + protected function getTraversable(bool $isHaltOnError): Generator { $this->log->debug( 'getTraversable.start', diff --git a/src/Core/Contracts/BatchInterface.php b/src/Core/Contracts/BatchInterface.php index 953f1fd4..a63d7440 100644 --- a/src/Core/Contracts/BatchInterface.php +++ b/src/Core/Contracts/BatchInterface.php @@ -30,12 +30,24 @@ interface BatchInterface public function getTraversableList(string $apiMethod, array $order, array $filter, array $select, ?int $limit = null): Generator; /** - * batch wrapper for *.add methods + * Add entity items with batch call * - * @param string $apiMethod - * @param array $entityItems + * @param string $apiMethod + * @param array $entityItems * - * @return Generator + * @return Generator|ResponseData[] + * @throws BaseException */ public function addEntityItems(string $apiMethod, array $entityItems): Generator; + + /** + * Delete entity items with batch call + * + * @param string $apiMethod + * @param array $entityItemId + * + * @return Generator|ResponseData[] + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function deleteEntityItems(string $apiMethod, array $entityItemId): Generator; } \ No newline at end of file diff --git a/src/Core/Core.php b/src/Core/Core.php index 13d2b05a..f5fb9deb 100644 --- a/src/Core/Core.php +++ b/src/Core/Core.php @@ -160,6 +160,7 @@ public function call(string $apiMethod, array $parameters = []): Response 'call.unknownException', [ 'message' => $exception->getMessage(), + 'trace' => $exception->getTrace(), ] ); throw new BaseException(sprintf('unknown error - %s', $exception->getMessage()), $exception->getCode(), $exception); diff --git a/tests/Integration/Core/BatchTest.php b/tests/Integration/Core/BatchTest.php new file mode 100644 index 00000000..77ab0c86 --- /dev/null +++ b/tests/Integration/Core/BatchTest.php @@ -0,0 +1,111 @@ +serviceBuilder->getCRMScope()->contact()->add( + [ + 'NAME' => sprintf('first_%s', time()), + 'SECOND' => sprintf('second_%s', time()), + ] + )->getId(); + $rawDeals = []; + for ($i = 0; $i < self::DEMO_DATA_ARRAY_SIZE; $i++) { + $rawDeals[] = [ + [ + 'fields' => [ + 'TITLE' => sprintf('deal-%s', $i), + 'OPPORTUNITY' => random_int(100, 40000), + 'CONTACT_ID' => $contactId, + ], + ], + ]; + } + + // add deals to bitrix24 + $dealIdList = []; + foreach ($this->batchService->addEntityItems('crm.deal.add', $rawDeals) as $cnt => $addDealResult) { + $dealIdList[] = $addDealResult->getResult()->getResultData()[0]; + } + $this->assertCount(self::DEMO_DATA_ARRAY_SIZE, $dealIdList); + } + + /** + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Exception + * @covers \Bitrix24\SDK\Core\Batch::addEntityItems + * @covers \Bitrix24\SDK\Core\Batch::deleteEntityItems + * @testdox Удаление сущностей в batch режиме + */ + public function testBatchDeleteCommand(): void + { + // prepare demo data + $contactId = $this->serviceBuilder->getCRMScope()->contact()->add( + [ + 'NAME' => sprintf('first_%s', time()), + 'SECOND' => sprintf('second_%s', time()), + ] + )->getId(); + $rawDeals = []; + for ($i = 0; $i < self::DEMO_DATA_ARRAY_SIZE; $i++) { + $rawDeals[] = [ + [ + 'fields' => [ + 'TITLE' => sprintf('deal-%s', $i), + 'OPPORTUNITY' => random_int(100, 40000), + 'CONTACT_ID' => $contactId, + ], + ], + ]; + } + + // add deals to bitrix24 + $dealIdList = []; + foreach ($this->batchService->addEntityItems('crm.deal.add', $rawDeals) as $cnt => $addDealResult) { + $dealIdList[] = $addDealResult->getResult()->getResultData()[0]; + } + $this->assertCount(self::DEMO_DATA_ARRAY_SIZE, $dealIdList); + + // delete deals from bitrix24 + $dealsDeleteResult = []; + foreach ($this->batchService->deleteEntityItems('crm.deal.delete', $dealIdList) as $cnt => $deleteDealResult) { + $dealsDeleteResult[] = $deleteDealResult->getResult()->getResultData()[0]; + } + $this->assertCount(self::DEMO_DATA_ARRAY_SIZE, $dealsDeleteResult); + } + + public function setUp(): void + { + $this->batchService = Fabric::getBatchService(); + $this->serviceBuilder = Fabric::getServiceBuilder(); + } + + public function tearDown(): void + { + } +} \ No newline at end of file diff --git a/tests/Integration/Fabric.php b/tests/Integration/Fabric.php index b808b82f..e7358c92 100644 --- a/tests/Integration/Fabric.php +++ b/tests/Integration/Fabric.php @@ -9,6 +9,7 @@ use Bitrix24\SDK\Services\ServiceBuilder; use Monolog\Handler\StreamHandler; use Monolog\Logger; +use Psr\Log\LoggerInterface; /** * Class Fabric @@ -23,12 +24,9 @@ class Fabric */ public static function getServiceBuilder(): ServiceBuilder { - $log = new Logger('integration-test'); - $log->pushHandler(new StreamHandler(STDOUT, (int)$_ENV['INTEGRATION_TEST_LOG_LEVEL'])); - $log->pushProcessor(new \Monolog\Processor\MemoryUsageProcessor(true, true)); - $log->pushProcessor(new \Monolog\Processor\IntrospectionProcessor()); - $log->debug('=============================================================='); + $log = self::getLogger(); + $log->debug('=============================================================='); $core = (new CoreBuilder()) ->withLogger($log) ->withWebhookUrl($_ENV['BITRIX24_WEBHOOK']) @@ -37,4 +35,33 @@ public static function getServiceBuilder(): ServiceBuilder return new ServiceBuilder($core, $batch, $log); } + + /** + * @return \Psr\Log\LoggerInterface + */ + private static function getLogger(): LoggerInterface + { + $log = new Logger('integration-test'); + $log->pushHandler(new StreamHandler(STDOUT, (int)$_ENV['INTEGRATION_TEST_LOG_LEVEL'])); + $log->pushProcessor(new \Monolog\Processor\MemoryUsageProcessor(true, true)); + $log->pushProcessor(new \Monolog\Processor\IntrospectionProcessor()); + + return $log; + } + + /** + * @return \Bitrix24\SDK\Core\Batch + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public static function getBatchService(): Batch + { + $log = self::getLogger(); + + return new Batch( + (new CoreBuilder()) + ->withLogger($log) + ->withWebhookUrl($_ENV['BITRIX24_WEBHOOK']) + ->build(), $log + ); + } } \ No newline at end of file diff --git a/tests/Unit/Stubs/NullBatch.php b/tests/Unit/Stubs/NullBatch.php index d6286ed8..25adf7b1 100644 --- a/tests/Unit/Stubs/NullBatch.php +++ b/tests/Unit/Stubs/NullBatch.php @@ -5,6 +5,8 @@ namespace Bitrix24\SDK\Tests\Unit\Stubs; use Bitrix24\SDK\Core\Contracts\BatchInterface; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Response\DTO\ResponseData; use Generator; /** @@ -29,13 +31,30 @@ public function getTraversableList(string $apiMethod, array $order, array $filte } /** - * @param string $apiMethod - * @param array $entityItems + * Add entity items with batch call * - * @return Generator + * @param string $apiMethod + * @param array $entityItems + * + * @return Generator|ResponseData[] + * @throws BaseException */ public function addEntityItems(string $apiMethod, array $entityItems): Generator { yield []; } + + /** + * Delete entity items with batch call + * + * @param string $apiMethod + * @param array $entityItemId + * + * @return Generator|ResponseData[] + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function deleteEntityItems(string $apiMethod, array $entityItemId): Generator + { + yield []; + } } \ No newline at end of file From 0eb45c920ade421181f27728f7f7e4d877226d6d Mon Sep 17 00:00:00 2001 From: mesilov Date: Tue, 18 Jan 2022 00:35:23 +0300 Subject: [PATCH 261/647] add types for dto Signed-off-by: mesilov --- src/Core/Response/DTO/ResponseData.php | 15 +++------------ src/Core/Response/DTO/Result.php | 5 +---- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/src/Core/Response/DTO/ResponseData.php b/src/Core/Response/DTO/ResponseData.php index 2605748a..655925fe 100644 --- a/src/Core/Response/DTO/ResponseData.php +++ b/src/Core/Response/DTO/ResponseData.php @@ -11,18 +11,9 @@ */ class ResponseData { - /** - * @var Result - */ - protected $result; - /** - * @var Time - */ - protected $time; - /** - * @var Pagination - */ - protected $pagination; + protected Result $result; + protected Time $time; + protected Pagination $pagination; /** * ResponseData constructor. diff --git a/src/Core/Response/DTO/Result.php b/src/Core/Response/DTO/Result.php index 251a6ff0..b5ddf9cc 100644 --- a/src/Core/Response/DTO/Result.php +++ b/src/Core/Response/DTO/Result.php @@ -11,10 +11,7 @@ */ class Result { - /** - * @var array - */ - protected $result; + protected array $result; /** * Result constructor. From 436764762e465f30c3ec1c2032f731ca5d1a3e4c Mon Sep 17 00:00:00 2001 From: mesilov Date: Tue, 18 Jan 2022 00:37:15 +0300 Subject: [PATCH 262/647] add symfony/stopwatch Signed-off-by: mesilov --- CHANGELOG.md | 3 ++- composer.json | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ed93a21..11fc3145 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,13 @@ # bitrix24-php-sdk change log -## 2.0-alpha.6 — 16.01.2021 +## 2.0-alpha.6 — 20.01.2021 ### Added * add «fast» batch-query without counting elements in result recordset [Добавить поддержку выгрузки большого количества данных без подсчёта элементов (-1](https://github.com/mesilov/bitrix24-php-sdk/issues/248) * add method `Core\Batch::deleteEntityItems` for delete items in batch mode and integration test +* add `symfony/stopwatch` component for integration tests ### Changed diff --git a/composer.json b/composer.json index ee87d098..7c92ae9d 100644 --- a/composer.json +++ b/composer.json @@ -34,6 +34,7 @@ "symfony/debug-bundle": "5.4.*", "phpstan/phpstan": "1.1.*", "phpunit/phpunit": "9.5.*", + "symfony/stopwatch": "5.4.*", "roave/security-advisories": "dev-master" }, "autoload": { From 869a87223ee6abe6337f76ba5b71d5d69ed7bbff Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 19 Jan 2022 01:02:44 +0300 Subject: [PATCH 263/647] add transport layer debug info Signed-off-by: mesilov --- CHANGELOG.md | 6 ++ src/Core/Response/Response.php | 25 ++++++ .../TransportLayer/NetworkTimingsParser.php | 84 +++++++++++++++++++ .../TransportLayer/ResponseInfoParser.php | 43 ++++++++++ tests/Integration/Core/CoreTest.php | 48 +++++++++++ tests/Integration/Fabric.php | 29 +++---- 6 files changed, 219 insertions(+), 16 deletions(-) create mode 100644 src/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser.php create mode 100644 src/Infrastructure/HttpClient/TransportLayer/ResponseInfoParser.php create mode 100644 tests/Integration/Core/CoreTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 11fc3145..f433a221 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,12 @@ recordset [Добавить поддержку выгрузки большого количества данных без подсчёта элементов (-1](https://github.com/mesilov/bitrix24-php-sdk/issues/248) * add method `Core\Batch::deleteEntityItems` for delete items in batch mode and integration test * add `symfony/stopwatch` component for integration tests +* add `/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser` for parse `curl_info` network data structures for debug logs + in `Bitrix24\SDK\Core\Response::__destruct()` +* add `/Infrastructure/HttpClient/TransportLayer/ResponseInfoParser` for parse `bitrix24_rest_api` timing info for debug logs + in `Bitrix24\SDK\Core\Response::__destruct()` +* add `Bitrix24\SDK\Core\BulkItemsReader` for data-intensive applications for bulk export data from Bitrix24, read strategies located in + folder `ReadStrategies`, in services read model **must** use most effective read strategy. ### Changed diff --git a/src/Core/Response/Response.php b/src/Core/Response/Response.php index 92ce2d47..f006e414 100644 --- a/src/Core/Response/Response.php +++ b/src/Core/Response/Response.php @@ -7,6 +7,8 @@ use Bitrix24\SDK\Core\Commands\Command; use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Response\DTO; +use Bitrix24\SDK\Infrastructure\HttpClient\TransportLayer\NetworkTimingsParser; +use Bitrix24\SDK\Infrastructure\HttpClient\TransportLayer\ResponseInfoParser; use Psr\Log\LoggerInterface; use Symfony\Contracts\HttpClient\ResponseInterface; use Throwable; @@ -54,6 +56,27 @@ 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->debug('Response.responseInfo', [ + 'restTimings' => $restTimings, + 'networkTimings' => (new NetworkTimingsParser($this->httpResponse->getInfo()))->toArrayWithMicroseconds(), + 'responseInfo' => (new ResponseInfoParser($this->httpResponse->getInfo()))->toArray(), + ]); + } + /** * @return DTO\ResponseData * @throws BaseException @@ -64,6 +87,7 @@ public function getResponseData(): DTO\ResponseData if ($this->responseData === null) { try { + $this->logger->debug('getResponseData.parseResponse.start'); $responseResult = $this->httpResponse->toArray(true); // try to handle api-level errors $this->handleApiLevelErrors($responseResult); @@ -86,6 +110,7 @@ public function getResponseData(): DTO\ResponseData DTO\Time::initFromResponse($responseResult['time']), new DTO\Pagination($nextItem, $total) ); + $this->logger->debug('getResponseData.parseResponse.finish'); } catch (Throwable $exception) { $this->logger->error( $exception->getMessage(), diff --git a/src/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser.php b/src/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser.php new file mode 100644 index 00000000..696a08a9 --- /dev/null +++ b/src/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser.php @@ -0,0 +1,84 @@ +networkTimings = [ + // name lookup time in MICROSECONDS + // https://curl.se/libcurl/c/CURLINFO_NAMELOOKUP_TIME.html + // get the name lookup time + // Time from the start until the name resolving was completed. + // When a redirect is followed, the time from each request is added together. + 'namelookup_time_us' => $httpClientResponseInfo['namelookup_time_us'], + + // total time in seconds from the start until the connection to the remote host (or proxy) was completed in MICROSECONDS + // https://curl.se/libcurl/c/CURLINFO_CONNECT_TIME.html + // When a redirect is followed, the time from each request is added together. + 'connect_time_us' => $httpClientResponseInfo['connect_time_us'], + + // time until the SSL/SSH handshake is completed in MICROSECONDS + // https://curl.se/libcurl/c/CURLINFO_APPCONNECT_TIME.html + // it took from the start until the SSL/SSH connect/handshake to the remote host was completed. + // This time is most often close to the CURLINFO_PRETRANSFER_TIME time, except for cases such as HTTP pipelining + // where the pretransfer time can be delayed due to waits in line for the pipeline and more. + // When a redirect is followed, the time from each request is added together. + 'appconnect_time_us' => $httpClientResponseInfo['appconnect_time_us'], + + // time until the file transfer start in MICROSECONDS + // https://curl.se/libcurl/c/CURLINFO_PRETRANSFER_TIME.html + // It took from the start until the file transfer is just about to begin. + // This time-stamp includes all pre-transfer commands and negotiations that are specific to the particular + // protocol(s) involved. It includes the sending of the protocol- specific protocol instructions that triggers a transfer. + // When a redirect is followed, the time from each request is added together. + 'pretransfer_time_us' => $httpClientResponseInfo['pretransfer_time_us'], + + // time for all redirection steps in MICROSECONDS + // https://curl.se/libcurl/c/CURLINFO_REDIRECT_TIME.html + // it took for all redirection steps include name lookup, connect, pretransfer and transfer before + // final transaction was started. + // CURLINFO_REDIRECT_TIME contains the complete execution time for multiple redirections. + 'redirect_time_us' => $httpClientResponseInfo['redirect_time_us'], + + // time until the first byte is received in MICROSECONDS + // it took from the start until the first byte is received by libcurl + // https://curl.se/libcurl/c/CURLINFO_STARTTRANSFER_TIME.html + // This includes CURLINFO_PRETRANSFER_TIME and also the time the server needs to calculate the result. + // When a redirect is followed, the time from each request is added together. + 'starttransfer_time_us' => $httpClientResponseInfo['starttransfer_time_us'], + + // total time of previous transfer in MICROSECONDS + // https://curl.se/libcurl/c/CURLINFO_TOTAL_TIME.html + // total time in seconds for the previous transfer, including name resolving, TCP connect etc. + // The double represents the time in seconds, including fractions. + // When a redirect is followed, the time from each request is added together. + 'total_time_us' => $httpClientResponseInfo['total_time_us'], + ]; + } + + /** + * @return array + */ + public function toArrayWithMicroseconds(): array + { + return $this->networkTimings; + } +} \ No newline at end of file diff --git a/src/Infrastructure/HttpClient/TransportLayer/ResponseInfoParser.php b/src/Infrastructure/HttpClient/TransportLayer/ResponseInfoParser.php new file mode 100644 index 00000000..386ba8e9 --- /dev/null +++ b/src/Infrastructure/HttpClient/TransportLayer/ResponseInfoParser.php @@ -0,0 +1,43 @@ +responseInfo = $httpClientResponseInfo; + } + + /** + * @return array[] + */ + public function toArray(): array + { + return [ + // canceled (bool) - true if the response was canceled using ResponseInterface::cancel(), false otherwise + 'canceled' => $this->responseInfo['canceled'], + // error (string|null) - the error message when the transfer was aborted, null otherwise + 'error' => $this->responseInfo['error'], + // http_code (int) - the last response code or 0 when it is not known yet + 'http_code' => $this->responseInfo['http_code'], + // http_method (string) - the HTTP verb of the last request + 'http_method' => $this->responseInfo['http_method'], + // redirect_count (int) - the number of redirects followed while executing the request + 'redirect_count' => $this->responseInfo['redirect_count'], + // redirect_url (string|null) - the resolved location of redirect responses, null otherwise + 'redirect_url' => $this->responseInfo['redirect_url'], + // start_time (float) - the time when the request was sent or 0.0 when it's pending + 'start_time' => $this->responseInfo['start_time'], + // url (string) - the last effective URL of the request + 'url' => $this->responseInfo['url'], + ]; + } +} \ No newline at end of file diff --git a/tests/Integration/Core/CoreTest.php b/tests/Integration/Core/CoreTest.php new file mode 100644 index 00000000..0d8d9132 --- /dev/null +++ b/tests/Integration/Core/CoreTest.php @@ -0,0 +1,48 @@ +core->call('app.info'); + $this->assertIsArray($response->getResponseData()->getResult()->getResultData()); + } + + /** + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function testCallUnknownApiMethod(): void + { + $this->expectException(MethodNotFoundException::class); + $response = $this->core->call('unknownMethod'); + } + + public function setUp(): void + { + $this->core = Fabric::getCore(); + $this->stopwatch = new Stopwatch(true); + $this->log = Fabric::getLogger(); + } +} \ No newline at end of file diff --git a/tests/Integration/Fabric.php b/tests/Integration/Fabric.php index e7358c92..dd156e5b 100644 --- a/tests/Integration/Fabric.php +++ b/tests/Integration/Fabric.php @@ -5,6 +5,7 @@ namespace Bitrix24\SDK\Tests\Integration; use Bitrix24\SDK\Core\Batch; +use Bitrix24\SDK\Core\Contracts\CoreInterface; use Bitrix24\SDK\Core\CoreBuilder; use Bitrix24\SDK\Services\ServiceBuilder; use Monolog\Handler\StreamHandler; @@ -24,22 +25,25 @@ class Fabric */ public static function getServiceBuilder(): ServiceBuilder { - $log = self::getLogger(); + return new ServiceBuilder(self::getCore(), self::getBatchService(), self::getLogger()); + } - $log->debug('=============================================================='); - $core = (new CoreBuilder()) - ->withLogger($log) + /** + * @return \Bitrix24\SDK\Core\Contracts\CoreInterface + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public static function getCore(): CoreInterface + { + return (new CoreBuilder()) + ->withLogger(self::getLogger()) ->withWebhookUrl($_ENV['BITRIX24_WEBHOOK']) ->build(); - $batch = new Batch($core, $log); - - return new ServiceBuilder($core, $batch, $log); } /** * @return \Psr\Log\LoggerInterface */ - private static function getLogger(): LoggerInterface + public static function getLogger(): LoggerInterface { $log = new Logger('integration-test'); $log->pushHandler(new StreamHandler(STDOUT, (int)$_ENV['INTEGRATION_TEST_LOG_LEVEL'])); @@ -55,13 +59,6 @@ private static function getLogger(): LoggerInterface */ public static function getBatchService(): Batch { - $log = self::getLogger(); - - return new Batch( - (new CoreBuilder()) - ->withLogger($log) - ->withWebhookUrl($_ENV['BITRIX24_WEBHOOK']) - ->build(), $log - ); + return new Batch(self::getCore(), self::getLogger()); } } \ No newline at end of file From eba8d900c4c4f45a8d3867ca3ff90bb0ee4276eb Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 19 Jan 2022 01:03:17 +0300 Subject: [PATCH 264/647] add BulkItemsReader Signed-off-by: mesilov --- src/Core/BulkItemsReader/BulkItemsReader.php | 43 ++++ .../BulkItemsReaderBuilder.php | 56 +++++ .../FilterWithoutBatchWithoutCountOrder.php | 217 ++++++++++++++++++ .../Contracts/BulkItemsReaderInterface.php | 25 ++ ...ilterWithoutBatchWithoutCountOrderTest.php | 159 +++++++++++++ 5 files changed, 500 insertions(+) create mode 100644 src/Core/BulkItemsReader/BulkItemsReader.php create mode 100644 src/Core/BulkItemsReader/BulkItemsReaderBuilder.php create mode 100644 src/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrder.php create mode 100644 src/Core/Contracts/BulkItemsReaderInterface.php create mode 100644 tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrderTest.php diff --git a/src/Core/BulkItemsReader/BulkItemsReader.php b/src/Core/BulkItemsReader/BulkItemsReader.php new file mode 100644 index 00000000..50a2809b --- /dev/null +++ b/src/Core/BulkItemsReader/BulkItemsReader.php @@ -0,0 +1,43 @@ +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 + { + foreach ($this->readStrategy->getTraversableList($apiMethod, $order, $filter, $select, $limit) as $cnt => $item) { + yield $cnt => $item; + } + } +} + diff --git a/src/Core/BulkItemsReader/BulkItemsReaderBuilder.php b/src/Core/BulkItemsReader/BulkItemsReaderBuilder.php new file mode 100644 index 00000000..86b9b42b --- /dev/null +++ b/src/Core/BulkItemsReader/BulkItemsReaderBuilder.php @@ -0,0 +1,56 @@ +core = $core; + $this->logger = $logger; + $this->readStrategy = $this->getOptimalReadStrategy(); + } + + /** + * @param \Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface $readStrategy + * + * @return BulkItemsReaderBuilder + */ + public function withReadStrategy(BulkItemsReaderInterface $readStrategy): BulkItemsReaderBuilder + { + $this->readStrategy = $readStrategy; + + return $this; + } + + /** + * @return \Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface + */ + protected function getOptimalReadStrategy(): BulkItemsReaderInterface + { + return new FilterWithoutBatchWithoutCountOrder($this->core, $this->logger); + } + + /** + * @return \Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface + */ + public function build(): BulkItemsReaderInterface + { + return new BulkItemsReader($this->readStrategy, $this->logger); + } +} \ No newline at end of file diff --git a/src/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrder.php b/src/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrder.php new file mode 100644 index 00000000..bc49bc7d --- /dev/null +++ b/src/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrder.php @@ -0,0 +1,217 @@ +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 + */ + public function getTraversableList(string $apiMethod, array $order, array $filter, array $select, ?int $limit = null): Generator + { + $this->log->debug('FilterWithoutBatchWithoutCountOrder.getTraversableList.start', [ + 'apiMethod' => $apiMethod, + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'limit' => $limit, + ]); + + // дефолтная стратегия из документации https://dev.1c-bitrix.ru/rest_help/rest_sum/start.php + // + //Особенности: + //— ✅ отключён подсчёт количества элементов в выборке + //— ⚠️ ID элементов в выборке возрастает, т.е. была сделана сортировка результатов по ID + //— не используем batch + //— ❗️ парсим ответ сервера для получения следующего ID → проблемы с распараллеливанием запросов + //— последовательное выполнение запросов + // + //Задел по оптимизации + //— ограниченное использование параллельных запросов + // + // Запросы отправляются к серверу последовательно с параметром "order": {"ID": "ASC"} (сортировка по возрастанию ID), + // и в каждом последующем запросе используются результаты предыдущего (фильтрация по ID, где ID > максимального ID в результатах + // предыдущего запроса). + // + // При этом для ускорения используется параметр start = -1 для отключения затратной по времени операции расчета общего + // количества записей (поле total), которое по умолчанию возвращается в каждом ответе сервера при вызове методов вида *.list. + // + // В потенциале для ускорения можно попытаться параллельно передвигаться по списку сущностей в два потока: + // с начала списка и с конца, продолжая получать страницы, пока ID в двух потоках не пересекутся. + // Такой способ, возможно, будет давать двукратное ускорение до тех пор, пока не будет исчерпан пул запросов к серверу и не + // потребуется включить throttling. + + + // get total elements count + + + // получили первый id элемента в выборке по фильтру + // todo проверили, что это *.list команда + // todo проверили, что в селекте есть ID, т.е. разработчик понимает, что ID используется + // todo проверили, что сортировка задана как "order": {"ID": "ASC"} т.е. разработчик понимает, что данные придут в таком порядке + // todo проверили, что если есть limit, то он >1 + // todo проверили, что в фильтре нет поля ID, т.к. мы с ним будем работать + + + $firstElementId = $this->getFirstElementId($apiMethod, $filter, $select); + if ($firstElementId === null) { + $this->log->debug('FilterWithoutBatchWithoutCountOrder.getTraversableList.emptySelect'); + + return; + } + $lastElementId = $this->getLastElementId($apiMethod, $filter, $select); + if ($lastElementId === null) { + $this->log->debug('FilterWithoutBatchWithoutCountOrder.getTraversableList.emptySelect'); + + return; + } + + // делаем запросы к Б24 + // todo учесть ретраии + // todo ограничения по количеству запросов в секунду + пул запросов + $currentElementId = $firstElementId; + $isStop = false; + while (!$isStop) { + $filterQuery = '>ID'; + if ($currentElementId === $firstElementId) { + $filterQuery = '>=ID'; + } + + $resultPage = $this->core->call( + $apiMethod, + [ + 'order' => ['ID' => 'ASC'], + 'filter' => array_merge( + [$filterQuery => $currentElementId], + $filter + ), + 'select' => array_unique(array_merge(['ID'], $select)), + 'start' => -1, + ] + ); + + + foreach ($resultPage->getResponseData()->getResult()->getResultData() as $cnt => $item) { + + + $currentElementId = (int)$item['ID']; + yield $cnt => $item; + } + + $this->log->debug('FilterWithoutBatchWithoutCountOrder.step', [ + 'duration' => $resultPage->getResponseData()->getTime()->getDuration(), + 'currentElementId' => $currentElementId, + 'lastElementId' => $lastElementId, + ]); + if ($currentElementId >= $lastElementId) { + $isStop = true; + } + } + } + + /** + * 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 Кандидат на вынос + */ + private function getFirstElementId(string $apiMethod, array $filter, array $select): ?int + { + $this->log->debug('FilterWithoutBatchWithoutCountOrder.getFirstElementId.start', [ + 'apiMethod' => $apiMethod, + 'filter' => $filter, + 'select' => $select, + ]); + + $firstResultPage = $this->core->call( + $apiMethod, + [ + 'order' => ['ID' => 'ASC'], + 'filter' => $filter, + 'select' => $select, + 'start' => 0, + ] + ); + + $elementId = $firstResultPage->getResponseData()->getResult()->getResultData()[0]['ID']; + + $this->log->debug('FilterWithoutBatchWithoutCountOrder.getFirstElementId.finish', [ + 'elementId' => $elementId, + ]); + + return $elementId === null ? null : (int)$elementId; + } + + /** + * Get first element id in filtered result ordered by id asc + * + * @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 Кандидат на вынос + */ + private function getLastElementId(string $apiMethod, array $filter, array $select): ?int + { + $this->log->debug('FilterWithoutBatchWithoutCountOrder.getLastElementId.start', [ + 'apiMethod' => $apiMethod, + 'filter' => $filter, + 'select' => $select, + ]); + + $lastResultPage = $this->core->call( + $apiMethod, + [ + 'order' => ['ID' => 'DESC'], + 'filter' => $filter, + 'select' => $select, + 'start' => 0, + ] + ); + + $elementId = $lastResultPage->getResponseData()->getResult()->getResultData()[0]['ID']; + + $this->log->debug('FilterWithoutBatchWithoutCountOrder.getLastElementId.finish', [ + 'elementId' => $elementId, + ]); + + return $elementId === null ? null : (int)$elementId; + } +} \ No newline at end of file diff --git a/src/Core/Contracts/BulkItemsReaderInterface.php b/src/Core/Contracts/BulkItemsReaderInterface.php new file mode 100644 index 00000000..c907316a --- /dev/null +++ b/src/Core/Contracts/BulkItemsReaderInterface.php @@ -0,0 +1,25 @@ +serviceBuilder->getCRMScope()->contact()->add( + [ + 'NAME' => sprintf('first_%s', time()), + 'SECOND' => sprintf('second_%s', time()), + ] + )->getId(); + + // add deals to bitrix24 + $rawDeals = []; + for ($i = 0; $i < self::DEMO_DATA_ARRAY_SIZE; $i++) { + $rawDeals[] = [ + 'TITLE' => sprintf('deal-%s', $i), + 'IS_MANUAL_OPPORTUNITY' => 'Y', + 'OPPORTUNITY' => sprintf('%s.00', random_int(100, 40000)), + 'CURRENCY_ID' => 'RUB', + 'CONTACT_ID' => $contactId, + ]; + } + $dealIdList = []; + foreach ($this->serviceBuilder->getCRMScope()->deal()->batch->add($rawDeals) as $addDealResult) { + $dealIdList[] = $addDealResult->getId(); + } + $this->assertCount(self::DEMO_DATA_ARRAY_SIZE, $dealIdList); + + // count added deals by default deal service + $filter = [ + 'CONTACT_ID' => $contactId, + ]; + + $elementsCountByFilter = $this->serviceBuilder->getCRMScope()->deal()->countByFilter($filter); + $this->assertEquals(self::DEMO_DATA_ARRAY_SIZE, $elementsCountByFilter); + + $select = [ + 'ID', + 'TITLE', + 'OPPORTUNITY', + ]; + + $elementsCount = 0; + $this->stopwatch->start('batch.list.with.count'); + foreach ($this->batch->getTraversableList('crm.deal.list', [], $filter, $select) as $cnt => $dealItem) { + $elementsCount++; +// print(sprintf( +// '%s-%s| %s | %s - %s', +// $cnt, +// $elementsCountByFilter, +// $dealItem['ID'], +// $dealItem['TITLE'], +// $dealItem['OPPORTUNITY'], +// ) . PHP_EOL); + } + $this->stopwatch->stop('batch.list.with.count'); + $this->assertEquals( + $elementsCountByFilter, + $elementsCount, + sprintf( + 'elements count by filter %s not equals elements count from batch %s', + $elementsCountByFilter, + $elementsCount + ) + ); + + + $elementsCount = 0; + $this->stopwatch->start('FilterWithoutBatchWithoutCountOrder'); + foreach ( + $this->bulkItemsReader->getTraversableList( + 'crm.deal.list', + ['ID' => 'ASC'], + $filter, + $select + ) as $cnt => $dealItem + ) { + $elementsCount++; +// print(sprintf( +// '%s-%s| %s | %s - %s', +// $cnt, +// $elementsCountByFilter, +// $dealItem['ID'], +// $dealItem['TITLE'], +// $dealItem['OPPORTUNITY'], +// ) . PHP_EOL); + } + $this->stopwatch->stop('FilterWithoutBatchWithoutCountOrder'); + $this->assertEquals( + $elementsCountByFilter, + $elementsCount, + sprintf( + 'elements count by filter %s not equals elements count from batch %s', + $elementsCountByFilter, + $elementsCount + ) + ); + + print('=====' . PHP_EOL); + print(sprintf( + 'duration for batch list with count: %s ms', + $this->stopwatch->getEvent('batch.list.with.count')->getDuration() + ) . PHP_EOL); + print(sprintf( + 'FilterWithoutBatchWithoutCountOrder: %s ms', + $this->stopwatch->getEvent('FilterWithoutBatchWithoutCountOrder')->getDuration() + ) . PHP_EOL); + + $this->assertTrue(true); + } + + public function setUp(): void + { + $this->stopwatch = new Stopwatch(true); + $this->batch = Fabric::getBatchService(); + $this->serviceBuilder = Fabric::getServiceBuilder(); + $this->log = Fabric::getLogger(); + $this->bulkItemsReader = new FilterWithoutBatchWithoutCountOrder( + Fabric::getCore(), + $this->log + ); + } + + public function tearDown(): void + { + } +} \ No newline at end of file From b73426aea9623df40e75d53fc681a864af9f2550 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 5 Feb 2022 08:44:40 +0300 Subject: [PATCH 265/647] set info log level for apiClient Signed-off-by: mesilov --- src/Core/ApiClient.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Core/ApiClient.php b/src/Core/ApiClient.php index 5ae6cf70..596b2511 100644 --- a/src/Core/ApiClient.php +++ b/src/Core/ApiClient.php @@ -121,7 +121,7 @@ public function getNewAccessToken(): RenewedAccessToken */ public function getResponse(string $apiMethod, array $parameters = []): ResponseInterface { - $this->logger->debug( + $this->logger->info( sprintf('getResponse.start %s', $apiMethod), [ 'domainUrl' => $this->credentials->getDomainUrl(), @@ -147,7 +147,7 @@ public function getResponse(string $apiMethod, array $parameters = []): Response ]; $response = $this->client->request($method, $url, $requestOptions); - $this->logger->debug( + $this->logger->info( sprintf('getResponse.end [%s]', $apiMethod), [ 'responseInfo' => $response->getInfo(), From f8cf02bdee08653e44d87f7cf8e0faf45772d84a Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 5 Feb 2022 08:45:13 +0300 Subject: [PATCH 266/647] add info level for Response Signed-off-by: mesilov --- src/Core/Response/Response.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Core/Response/Response.php b/src/Core/Response/Response.php index f006e414..81f53b58 100644 --- a/src/Core/Response/Response.php +++ b/src/Core/Response/Response.php @@ -70,7 +70,7 @@ public function __destruct() 'rest_query_finish' => $this->responseData->getTime()->getFinish(), ]; } - $this->logger->debug('Response.responseInfo', [ + $this->logger->info('Response.TransportInfo', [ 'restTimings' => $restTimings, 'networkTimings' => (new NetworkTimingsParser($this->httpResponse->getInfo()))->toArrayWithMicroseconds(), 'responseInfo' => (new ResponseInfoParser($this->httpResponse->getInfo()))->toArray(), @@ -89,6 +89,9 @@ public function getResponseData(): DTO\ResponseData try { $this->logger->debug('getResponseData.parseResponse.start'); $responseResult = $this->httpResponse->toArray(true); + $this->logger->info('getResponseData.responseBody', [ + 'responseBody' => $responseResult, + ]); // try to handle api-level errors $this->handleApiLevelErrors($responseResult); From 96017d43b71ee8175095628cbc96352b4f0efd64 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 5 Feb 2022 08:46:37 +0300 Subject: [PATCH 267/647] fix BulkItemsReaderBuilder Signed-off-by: mesilov --- .../BulkItemsReaderBuilder.php | 16 ++++-- .../FilterWithBatchWithoutCountOrder.php | 54 +++++++++++++++++++ .../Contracts/BulkItemsReaderInterface.php | 4 +- 3 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 src/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrder.php diff --git a/src/Core/BulkItemsReader/BulkItemsReaderBuilder.php b/src/Core/BulkItemsReader/BulkItemsReaderBuilder.php index 86b9b42b..32e99a0e 100644 --- a/src/Core/BulkItemsReader/BulkItemsReaderBuilder.php +++ b/src/Core/BulkItemsReader/BulkItemsReaderBuilder.php @@ -4,7 +4,8 @@ namespace Bitrix24\SDK\Core\BulkItemsReader; -use Bitrix24\SDK\Core\BulkItemsReader\ReadStrategies\FilterWithoutBatchWithoutCountOrder; +use Bitrix24\SDK\Core\BulkItemsReader\ReadStrategies\FilterWithBatchWithoutCountOrder; +use Bitrix24\SDK\Core\Contracts\BatchInterface; use Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface; use Bitrix24\SDK\Core\Contracts\CoreInterface; use Psr\Log\LoggerInterface; @@ -12,16 +13,19 @@ class BulkItemsReaderBuilder { protected CoreInterface $core; + protected BatchInterface $batch; protected LoggerInterface $logger; protected BulkItemsReaderInterface $readStrategy; /** - * @param \Bitrix24\SDK\Core\Contracts\CoreInterface $core - * @param \Psr\Log\LoggerInterface $logger + * @param \Bitrix24\SDK\Core\Contracts\CoreInterface $core + * @param \Bitrix24\SDK\Core\Contracts\BatchInterface $batch + * @param \Psr\Log\LoggerInterface $logger */ - public function __construct(CoreInterface $core, LoggerInterface $logger) + public function __construct(CoreInterface $core, BatchInterface $batch, LoggerInterface $logger) { $this->core = $core; + $this->batch = $batch; $this->logger = $logger; $this->readStrategy = $this->getOptimalReadStrategy(); } @@ -39,11 +43,13 @@ public function withReadStrategy(BulkItemsReaderInterface $readStrategy): BulkIt } /** + * 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 FilterWithoutBatchWithoutCountOrder($this->core, $this->logger); + return new FilterWithBatchWithoutCountOrder($this->batch, $this->logger); } /** diff --git a/src/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrder.php b/src/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrder.php new file mode 100644 index 00000000..ef58f410 --- /dev/null +++ b/src/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrder.php @@ -0,0 +1,54 @@ +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 + */ + public function getTraversableList(string $apiMethod, array $order, array $filter, array $select, ?int $limit = null): Generator + { + $this->log->debug('FilterWithBatchWithoutCountOrder.getTraversableList.start', [ + 'apiMethod' => $apiMethod, + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'limit' => $limit, + ]); + + foreach ($this->batch->getTraversableList($apiMethod, $order, $filter, $select, $limit) as $cnt => $resultItem) { + yield $cnt => $resultItem; + } + + $this->log->debug('FilterWithBatchWithoutCountOrder.getTraversableList.finish'); + } +} \ No newline at end of file diff --git a/src/Core/Contracts/BulkItemsReaderInterface.php b/src/Core/Contracts/BulkItemsReaderInterface.php index c907316a..515dcb55 100644 --- a/src/Core/Contracts/BulkItemsReaderInterface.php +++ b/src/Core/Contracts/BulkItemsReaderInterface.php @@ -10,7 +10,9 @@ interface BulkItemsReaderInterface { /** - * wrapper for *.list methods for bulk items read + * Wrapper for *.list methods for optimized bulk items read + * + * This reader used performance optimized read strategy selected by integrations tests * * @param string $apiMethod *.list method * @param array $order elements order From 6cd2c4b8a82f63aaad0ed1762bfff8668c06f45b Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 5 Feb 2022 08:47:36 +0300 Subject: [PATCH 268/647] add BulkItemsReaderBuilder for services Signed-off-by: mesilov --- src/Services/AbstractServiceBuilder.php | 18 ++++++--- src/Services/ServiceBuilder.php | 6 +-- .../Services/CRM/CRMServiceBuilderTest.php | 8 +++- .../Unit/Services/IM/IMServiceBuilderTest.php | 10 ++++- .../Services/Main/MainServiceBuilderTest.php | 9 ++++- tests/Unit/Services/ServiceBuilderTest.php | 8 +++- tests/Unit/Stubs/NullBatch.php | 40 ++++++++----------- tests/Unit/Stubs/NullBulkItemsReader.php | 19 +++++++++ 8 files changed, 81 insertions(+), 37 deletions(-) create mode 100644 tests/Unit/Stubs/NullBulkItemsReader.php diff --git a/src/Services/AbstractServiceBuilder.php b/src/Services/AbstractServiceBuilder.php index ee7cac7d..186b5867 100644 --- a/src/Services/AbstractServiceBuilder.php +++ b/src/Services/AbstractServiceBuilder.php @@ -6,6 +6,7 @@ use Bitrix24\SDK\Core\Contracts\BatchInterface; +use Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface; use Bitrix24\SDK\Core\Contracts\CoreInterface; use Psr\Log\LoggerInterface; @@ -18,20 +19,27 @@ abstract class AbstractServiceBuilder { protected CoreInterface $core; protected BatchInterface $batch; + protected BulkItemsReaderInterface $bulkItemsReader; protected LoggerInterface $log; protected array $serviceCache; /** * AbstractServiceBuilder constructor. * - * @param CoreInterface $core - * @param BatchInterface $batch - * @param LoggerInterface $log + * @param CoreInterface $core + * @param BatchInterface $batch + * @param \Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface $bulkItemsReader + * @param LoggerInterface $log */ - public function __construct(CoreInterface $core, BatchInterface $batch, LoggerInterface $log) - { + public function __construct( + CoreInterface $core, + BatchInterface $batch, + BulkItemsReaderInterface $bulkItemsReader, + LoggerInterface $log + ) { $this->core = $core; $this->batch = $batch; + $this->bulkItemsReader = $bulkItemsReader; $this->log = $log; } } \ No newline at end of file diff --git a/src/Services/ServiceBuilder.php b/src/Services/ServiceBuilder.php index 86f05279..fa8a51a9 100644 --- a/src/Services/ServiceBuilder.php +++ b/src/Services/ServiceBuilder.php @@ -21,7 +21,7 @@ class ServiceBuilder extends AbstractServiceBuilder public function getCRMScope(): CRMServiceBuilder { if (!isset($this->serviceCache[__METHOD__])) { - $this->serviceCache[__METHOD__] = new CRMServiceBuilder($this->core, $this->batch, $this->log); + $this->serviceCache[__METHOD__] = new CRMServiceBuilder($this->core, $this->batch, $this->bulkItemsReader, $this->log); } return $this->serviceCache[__METHOD__]; @@ -33,7 +33,7 @@ public function getCRMScope(): CRMServiceBuilder public function getIMScope(): IMServiceBuilder { if (!isset($this->serviceCache[__METHOD__])) { - $this->serviceCache[__METHOD__] = new IMServiceBuilder($this->core, $this->batch, $this->log); + $this->serviceCache[__METHOD__] = new IMServiceBuilder($this->core, $this->batch, $this->bulkItemsReader, $this->log); } return $this->serviceCache[__METHOD__]; @@ -45,7 +45,7 @@ public function getIMScope(): IMServiceBuilder public function getMainScope(): MainServiceBuilder { if (!isset($this->serviceCache[__METHOD__])) { - $this->serviceCache[__METHOD__] = new MainServiceBuilder($this->core, $this->batch, $this->log); + $this->serviceCache[__METHOD__] = new MainServiceBuilder($this->core, $this->batch, $this->bulkItemsReader, $this->log); } return $this->serviceCache[__METHOD__]; diff --git a/tests/Unit/Services/CRM/CRMServiceBuilderTest.php b/tests/Unit/Services/CRM/CRMServiceBuilderTest.php index 7084603e..d72586c3 100644 --- a/tests/Unit/Services/CRM/CRMServiceBuilderTest.php +++ b/tests/Unit/Services/CRM/CRMServiceBuilderTest.php @@ -7,6 +7,7 @@ use Bitrix24\SDK\Services\CRM\CRMServiceBuilder; use Bitrix24\SDK\Services\ServiceBuilder; use Bitrix24\SDK\Tests\Unit\Stubs\NullBatch; +use Bitrix24\SDK\Tests\Unit\Stubs\NullBulkItemsReader; use Bitrix24\SDK\Tests\Unit\Stubs\NullCore; use PHPUnit\Framework\TestCase; use Psr\Log\NullLogger; @@ -85,6 +86,11 @@ public function testDealCategoryStageService(): void public function setUp(): void { - $this->serviceBuilder = (new ServiceBuilder(new NullCore(), new NullBatch(), new NullLogger()))->getCRMScope(); + $this->serviceBuilder = (new ServiceBuilder( + new NullCore(), + new NullBatch(), + new NullBulkItemsReader(), + new NullLogger() + ))->getCRMScope(); } } \ No newline at end of file diff --git a/tests/Unit/Services/IM/IMServiceBuilderTest.php b/tests/Unit/Services/IM/IMServiceBuilderTest.php index 37384826..21b7d228 100644 --- a/tests/Unit/Services/IM/IMServiceBuilderTest.php +++ b/tests/Unit/Services/IM/IMServiceBuilderTest.php @@ -7,6 +7,7 @@ use Bitrix24\SDK\Services\IM\IMServiceBuilder; use Bitrix24\SDK\Services\ServiceBuilder; use Bitrix24\SDK\Tests\Unit\Stubs\NullBatch; +use Bitrix24\SDK\Tests\Unit\Stubs\NullBulkItemsReader; use Bitrix24\SDK\Tests\Unit\Stubs\NullCore; use PHPUnit\Framework\TestCase; use Psr\Log\NullLogger; @@ -29,9 +30,14 @@ public function testGetIMService(): void $this::assertTrue(true); } - public function setUp(): void { - $this->serviceBuilder = (new ServiceBuilder(new NullCore(), new NullBatch(), new NullLogger()))->getIMScope(); + $this->serviceBuilder = ( + new ServiceBuilder( + new NullCore(), + new NullBatch(), + new NullBulkItemsReader(), + new NullLogger() + ))->getIMScope(); } } \ No newline at end of file diff --git a/tests/Unit/Services/Main/MainServiceBuilderTest.php b/tests/Unit/Services/Main/MainServiceBuilderTest.php index 710084b2..c90df171 100644 --- a/tests/Unit/Services/Main/MainServiceBuilderTest.php +++ b/tests/Unit/Services/Main/MainServiceBuilderTest.php @@ -7,6 +7,7 @@ use Bitrix24\SDK\Services\Main\MainServiceBuilder; use Bitrix24\SDK\Services\ServiceBuilder; use Bitrix24\SDK\Tests\Unit\Stubs\NullBatch; +use Bitrix24\SDK\Tests\Unit\Stubs\NullBulkItemsReader; use Bitrix24\SDK\Tests\Unit\Stubs\NullCore; use PHPUnit\Framework\TestCase; use Psr\Log\NullLogger; @@ -29,9 +30,13 @@ public function testGetMainService(): void $this::assertTrue(true); } - public function setUp(): void { - $this->serviceBuilder = (new ServiceBuilder(new NullCore(), new NullBatch(), new NullLogger()))->getMainScope(); + $this->serviceBuilder = (new ServiceBuilder( + new NullCore(), + new NullBatch(), + new NullBulkItemsReader(), + new NullLogger() + ))->getMainScope(); } } \ No newline at end of file diff --git a/tests/Unit/Services/ServiceBuilderTest.php b/tests/Unit/Services/ServiceBuilderTest.php index 2bc8b03d..9a8abe94 100644 --- a/tests/Unit/Services/ServiceBuilderTest.php +++ b/tests/Unit/Services/ServiceBuilderTest.php @@ -6,6 +6,7 @@ use Bitrix24\SDK\Services\ServiceBuilder; use Bitrix24\SDK\Tests\Unit\Stubs\NullBatch; +use Bitrix24\SDK\Tests\Unit\Stubs\NullBulkItemsReader; use Bitrix24\SDK\Tests\Unit\Stubs\NullCore; use PHPUnit\Framework\TestCase; use Psr\Log\NullLogger; @@ -48,6 +49,11 @@ public function testGetCrmScopeBuilder(): void public function setUp(): void { - $this->serviceBuilder = new ServiceBuilder(new NullCore(), new NullBatch(), new NullLogger()); + $this->serviceBuilder = new ServiceBuilder( + new NullCore(), + new NullBatch(), + new NullBulkItemsReader(), + new NullLogger() + ); } } \ No newline at end of file diff --git a/tests/Unit/Stubs/NullBatch.php b/tests/Unit/Stubs/NullBatch.php index 25adf7b1..efd8ab43 100644 --- a/tests/Unit/Stubs/NullBatch.php +++ b/tests/Unit/Stubs/NullBatch.php @@ -5,8 +5,6 @@ namespace Bitrix24\SDK\Tests\Unit\Stubs; use Bitrix24\SDK\Core\Contracts\BatchInterface; -use Bitrix24\SDK\Core\Exceptions\BaseException; -use Bitrix24\SDK\Core\Response\DTO\ResponseData; use Generator; /** @@ -16,14 +14,9 @@ */ class NullBatch implements BatchInterface { + /** - * @param string $apiMethod - * @param array $order - * @param array $filter - * @param array $select - * @param int|null $limit - * - * @return Generator + * @inheritDoc */ public function getTraversableList(string $apiMethod, array $order, array $filter, array $select, ?int $limit = null): Generator { @@ -31,13 +24,20 @@ public function getTraversableList(string $apiMethod, array $order, array $filte } /** - * Add entity items with batch call - * - * @param string $apiMethod - * @param array $entityItems - * - * @return Generator|ResponseData[] - * @throws BaseException + * @inheritDoc + */ + public function getTraversableListWithCount( + string $apiMethod, + array $order, + array $filter, + array $select, + ?int $limit = null + ): Generator { + yield []; + } + + /** + * @inheritDoc */ public function addEntityItems(string $apiMethod, array $entityItems): Generator { @@ -45,13 +45,7 @@ public function addEntityItems(string $apiMethod, array $entityItems): Generator } /** - * Delete entity items with batch call - * - * @param string $apiMethod - * @param array $entityItemId - * - * @return Generator|ResponseData[] - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @inheritDoc */ public function deleteEntityItems(string $apiMethod, array $entityItemId): Generator { diff --git a/tests/Unit/Stubs/NullBulkItemsReader.php b/tests/Unit/Stubs/NullBulkItemsReader.php new file mode 100644 index 00000000..9f2b8500 --- /dev/null +++ b/tests/Unit/Stubs/NullBulkItemsReader.php @@ -0,0 +1,19 @@ + Date: Sat, 5 Feb 2022 08:48:52 +0300 Subject: [PATCH 269/647] add BulkItemsReaderBuilder for integration test Signed-off-by: mesilov --- tests/Integration/Fabric.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/Integration/Fabric.php b/tests/Integration/Fabric.php index dd156e5b..ada1d33f 100644 --- a/tests/Integration/Fabric.php +++ b/tests/Integration/Fabric.php @@ -5,6 +5,8 @@ namespace Bitrix24\SDK\Tests\Integration; use Bitrix24\SDK\Core\Batch; +use Bitrix24\SDK\Core\BulkItemsReader\BulkItemsReaderBuilder; +use Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface; use Bitrix24\SDK\Core\Contracts\CoreInterface; use Bitrix24\SDK\Core\CoreBuilder; use Bitrix24\SDK\Services\ServiceBuilder; @@ -25,7 +27,16 @@ class Fabric */ public static function getServiceBuilder(): ServiceBuilder { - return new ServiceBuilder(self::getCore(), self::getBatchService(), self::getLogger()); + return new ServiceBuilder(self::getCore(), self::getBatchService(), self::getBulkItemsReader(), self::getLogger()); + } + + /** + * @return \Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public static function getBulkItemsReader(): BulkItemsReaderInterface + { + return (new BulkItemsReaderBuilder(self::getCore(), self::getBatchService(), self::getLogger()))->build(); } /** From b4cdbdd430f9b2669cf90e8279063d4e3e5098f9 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 5 Feb 2022 08:49:58 +0300 Subject: [PATCH 270/647] add getTraversableList for batch Signed-off-by: mesilov --- src/Core/Batch.php | 331 ++++++++++++++++---------- src/Core/Contracts/BatchInterface.php | 36 ++- 2 files changed, 242 insertions(+), 125 deletions(-) diff --git a/src/Core/Batch.php b/src/Core/Batch.php index 0e77af84..134b1732 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -25,7 +25,7 @@ class Batch implements BatchInterface { private CoreInterface $core; - private LoggerInterface $log; + private LoggerInterface $logger; protected const MAX_BATCH_PACKET_SIZE = 50; protected const MAX_ELEMENTS_IN_PAGE = 50; protected CommandCollection $commands; @@ -39,7 +39,7 @@ class Batch implements BatchInterface public function __construct(CoreInterface $core, LoggerInterface $log) { $this->core = $core; - $this->log = $log; + $this->logger = $log; $this->commands = new CommandCollection(); } @@ -48,14 +48,14 @@ public function __construct(CoreInterface $core, LoggerInterface $log) */ protected function clearCommands(): void { - $this->log->debug( + $this->logger->debug( 'clearCommands.start', [ 'commandsCount' => $this->commands->count(), ] ); $this->commands = new CommandCollection(); - $this->log->debug('clearCommands.finish'); + $this->logger->debug('clearCommands.finish'); } /** @@ -69,7 +69,7 @@ protected function clearCommands(): void */ public function addEntityItems(string $apiMethod, array $entityItems): Generator { - $this->log->debug( + $this->logger->debug( 'addEntityItems.start', [ 'apiMethod' => $apiMethod, @@ -88,7 +88,7 @@ public function addEntityItems(string $apiMethod, array $entityItems): Generator } } catch (\Throwable $exception) { $errorMessage = sprintf('batch add entity items: %s', $exception->getMessage()); - $this->log->error( + $this->logger->error( $errorMessage, [ 'trace' => $exception->getTrace(), @@ -98,7 +98,7 @@ public function addEntityItems(string $apiMethod, array $entityItems): Generator throw new BaseException($errorMessage, $exception->getCode(), $exception); } - $this->log->debug('addEntityItems.finish'); + $this->logger->debug('addEntityItems.finish'); } /** @@ -112,7 +112,7 @@ public function addEntityItems(string $apiMethod, array $entityItems): Generator */ public function deleteEntityItems(string $apiMethod, array $entityItemId): Generator { - $this->log->debug( + $this->logger->debug( 'deleteEntityItems.start', [ 'apiMethod' => $apiMethod, @@ -131,7 +131,7 @@ public function deleteEntityItems(string $apiMethod, array $entityItemId): Gener } } catch (\Throwable $exception) { $errorMessage = sprintf('batch delete entity items: %s', $exception->getMessage()); - $this->log->error( + $this->logger->error( $errorMessage, [ 'trace' => $exception->getTrace(), @@ -141,7 +141,7 @@ public function deleteEntityItems(string $apiMethod, array $entityItemId): Gener throw new BaseException($errorMessage, $exception->getCode(), $exception); } - $this->log->debug('deleteEntityItems.finish'); + $this->logger->debug('deleteEntityItems.finish'); } /** @@ -150,7 +150,7 @@ public function deleteEntityItems(string $apiMethod, array $entityItemId): Gener * @param string $apiMethod * @param array $parameters * @param string|null $commandName - * @param callable|null $callback + * @param callable|null $callback not implemented * * @throws \Exception */ @@ -160,7 +160,7 @@ protected function registerCommand( ?string $commandName = null, callable $callback = null ): void { - $this->log->debug( + $this->logger->debug( 'registerCommand.start', [ 'apiMethod' => $apiMethod, @@ -171,7 +171,7 @@ protected function registerCommand( $this->commands->attach(new Command($apiMethod, $parameters, $commandName)); - $this->log->debug( + $this->logger->debug( 'registerCommand.finish', [ 'commandsCount' => $this->commands->count(), @@ -186,7 +186,7 @@ protected function registerCommand( */ protected function getReverseOrder(array $order): array { - $this->log->debug( + $this->logger->debug( 'getReverseOrder.start', [ 'order' => $order, @@ -196,18 +196,18 @@ protected function getReverseOrder(array $order): array if ($order === []) { $reverseOrder = ['ID' => 'DESC']; - } - - $order = array_change_key_case($order, CASE_UPPER); - $oldDirection = array_values($order)[0]; - if ($oldDirection === 'ASC') { - $newOrderDirection = 'DESC'; } else { - $newOrderDirection = 'ASC'; + $order = array_change_key_case($order, CASE_UPPER); + $oldDirection = array_values($order)[0]; + if ($oldDirection === 'ASC') { + $newOrderDirection = 'DESC'; + } else { + $newOrderDirection = 'ASC'; + } + $reverseOrder[array_key_first($order)] = $newOrderDirection; } - $reverseOrder[array_key_first($order)] = $newOrderDirection; - $this->log->debug( + $this->logger->debug( 'getReverseOrder.finish', [ 'order' => $reverseOrder, @@ -218,7 +218,7 @@ protected function getReverseOrder(array $order): array } /** - * WORK IN PROGRESS + * Get traversable list without count elements * * @param string $apiMethod * @param array $order @@ -235,118 +235,200 @@ protected function getReverseOrder(array $order): array * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface * @throws \Exception */ - public function getTraversableListWithoutCount( + public function getTraversableList( string $apiMethod, array $order, array $filter, array $select, ?int $limit = null ): Generator { - $this->log->debug( - 'getTraversableListWithoutCount.start', + $this->logger->debug('getTraversableList.start', + [ + 'apiMethod' => $apiMethod, + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'limit' => $limit, + ] + ); + + // strategy.3 — ID filter, batch, no count, order + // — ✅ отключён подсчёт количества элементов в выборке + // — ⚠️ ID элементов в выборке возрастает, т.е. была сделана сортировка результатов по ID + // — используем batch + // — последовательное выполнение запросов + // + // Задел по оптимизации + // — ограниченное использование параллельных запросов + // + // Запросы отправляются к серверу последовательно с параметром "order": {"ID": "ASC"} (сортировка по возрастанию ID). + // Т.к. результаты отсортированы по возрастанию ID, то их можно объеденить в батч-запросы с отключённым подсчётом количества элементов в каждом. + // + // Порядок формирования фильтра: + // + // взяли фильтр с «прямой» сортировкой и получили первый ID + // взяли фильтр с «обратной» сортировкой и получили последний ID + // Т.к. ID монотонно возрастает, то делаем предположение, что все страницы заполнены элементами равномерно, на самом деле там будут «дыры» из-за мастер-мастер репликации и удалённых элементов. т.е. в результирующих выборках не всегда будет ровно 50 элементов. + // из готовых фильтров формируем выборки и упаковываем их в батч-команды. + // по возможности, батч-запросы выполняются параллельно + + // получили первый id элемента в выборке по фильтру + // todo проверили, что это *.list команда + // todo проверили, что в селекте есть ID, т.е. разработчик понимает, что ID используется + // todo проверили, что сортировка задана как "order": {"ID": "ASC"} т.е. разработчик понимает, что данные придут в таком порядке + // todo проверили, что если есть limit, то он >1 + // todo проверили, что в фильтре нет поля ID, т.к. мы с ним будем работать + + + $firstResultPage = $this->core->call( + $apiMethod, [ - 'apiMethod' => $apiMethod, - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'limit' => $limit, + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => 0, ] ); - $this->clearCommands(); + $totalElementsCount = $firstResultPage->getResponseData()->getPagination()->getTotal(); + // filtered elements count less than or equal one result page(50 elements) + $elementsCounter = 0; + if ($totalElementsCount <= self::MAX_ELEMENTS_IN_PAGE) { + foreach ($firstResultPage->getResponseData()->getResult()->getResultData() as $cnt => $listElement) { + $elementsCounter++; + if ($limit !== null && $elementsCounter > $limit) { + return; + } + yield $listElement; + } + $this->logger->debug('getTraversableList.finish'); + + return; + } + // filtered elements count more than one result page(50 elements) + // return first page + $lastElementIdInFirstPage = null; + foreach ($firstResultPage->getResponseData()->getResult()->getResultData() as $cnt => $listElement) { + $elementsCounter++; + $lastElementIdInFirstPage = $listElement['ID']; + if ($limit !== null && $elementsCounter > $limit) { + return; + } + yield $listElement; + } + + $this->clearCommands(); if (!in_array('ID', $select, true)) { $select[] = 'ID'; } - // get total elements count - $firstResult = $this->core->call( + + // getLastElementId in filtered result + $lastResultPage = $this->core->call( $apiMethod, [ - 'order' => $order, + 'order' => $this->getReverseOrder($order), 'filter' => $filter, 'select' => $select, 'start' => 0, ] ); - $nextItem = $firstResult->getResponseData()->getPagination()->getNextItem(); - $total = $firstResult->getResponseData()->getPagination()->getTotal(); - $this->log->debug( - 'getTraversableListWithoutCount.calculateCommandsRange', - [ - 'totalItems' => $total, - ] - ); - if ($total > self::MAX_ELEMENTS_IN_PAGE && $nextItem !== null) { - //more than one page in results - register list commands - $reverseOrder = $this->getReverseOrder($order); - $firstId = $firstResult->getResponseData()->getResult()->getResultData()[0]['ID']; + $lastElementId = (int)$lastResultPage->getResponseData()->getResult()->getResultData()[0]['ID']; + + // register commands with updated filter + //more than one page in results - register list commands + $lastElementIdInFirstPage++; + for ($startId = $lastElementIdInFirstPage; $startId <= $lastElementId; $startId += self::MAX_ELEMENTS_IN_PAGE) { + $this->logger->debug('registerCommand.item', [ + 'startId' => $startId, + 'lastElementId' => $lastElementId, + 'delta' => $lastElementId - $startId, + ]); + + $delta = $lastElementId - $startId; + $isLastPage = false; + if ($delta > self::MAX_ELEMENTS_IN_PAGE) { + // ignore + // - master–master replication with id + // - deleted elements + $lastElementIdInPage = $startId + self::MAX_ELEMENTS_IN_PAGE; + } else { + $lastElementIdInPage = $lastElementId; + $isLastPage = true; + } - $lastId = $this->core->call( + $this->registerCommand( $apiMethod, [ - 'order' => $reverseOrder, - 'filter' => $filter, + 'order' => [], + 'filter' => $this->updateFilterForBatch($startId, $lastElementIdInPage, $isLastPage, $filter), 'select' => $select, - 'start' => 0, + 'start' => -1, ] - )->getResponseData()->getResult()->getResultData()[0]['ID']; - - //more than one page in results - register list commands - for ($startId = $firstId; $startId <= $lastId; $startId += self::MAX_ELEMENTS_IN_PAGE) { - $this->registerCommand( - $apiMethod, - [ - 'order' => [], - 'filter' => ['>=ID' => $startId], - 'select' => $select, - 'start' => -1, - ] - ); - } + ); + } + $this->logger->debug( + 'getTraversableList.commandsRegistered', + [ + 'commandsCount' => $this->commands->count(), + ] + ); - $this->log->debug( - 'getTraversableList.commandsRegistered', + // iterate batch queries, max: 50 results per 50 elements in each result + $elementsCounter = 0; + foreach ($this->getTraversable(true) as $queryCnt => $queryResultData) { + /** + * @var $queryResultData ResponseData + */ + $this->logger->debug( + 'getTraversableList.batchResultItem', [ - 'commandsCount' => $this->commands->count(), - 'totalItemsToSelect' => $total, + 'batchCommandItemNumber' => $queryCnt, + 'nextItem' => $queryResultData->getPagination()->getNextItem(), + 'durationTime' => $queryResultData->getTime()->getDuration(), ] ); - - // iterate batch queries, max: 50 results per 50 elements in each result - $elementsCounter = 0; - foreach ($this->getTraversable(true) as $queryCnt => $queryResultData) { - /** - * @var $queryResultData ResponseData - */ - $this->log->debug( - 'getTraversableList.batchResultItem', - [ - 'batchCommandItemNumber' => $queryCnt, - 'nextItem' => $queryResultData->getPagination()->getNextItem(), - 'durationTime' => $queryResultData->getTime()->getDuration(), - ] - ); - // iterate items in batch query result - foreach ($queryResultData->getResult()->getResultData() as $cnt => $listElement) { - $elementsCounter++; - if ($limit !== null && $elementsCounter > $limit) { - return; - } - yield $listElement; + // iterate items in batch query result + foreach ($queryResultData->getResult()->getResultData() as $cnt => $listElement) { + $elementsCounter++; + if ($limit !== null && $elementsCounter > $limit) { + return; } + yield $listElement; } - } else { - // one page in results - $this->registerCommand( - $apiMethod, - [ - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'start' => 0, - ] - ); } + $this->logger->debug('getTraversableList.finish'); + } + + /** + * @param int $startElementId + * @param int $lastElementId + * @param bool $isLastPage + * @param array $oldFilter + * + * @return array + */ + protected function updateFilterForBatch(int $startElementId, int $lastElementId, bool $isLastPage, array $oldFilter): array + { + $this->logger->debug('updateFilterForBatch.start', [ + 'startElementId' => $startElementId, + 'lastElementId' => $lastElementId, + 'isLastPage' => $isLastPage, + 'oldFilter' => $oldFilter, + ]); + + $filter = array_merge( + $oldFilter, + [ + '>=ID' => $startElementId, + $isLastPage ? '<=ID' : ' $lastElementId, + ] + ); + $this->logger->debug('updateFilterForBatch.finish', [ + 'filter' => $filter, + ]); + + return $filter; } /** @@ -360,7 +442,7 @@ public function getTraversableListWithoutCount( * @param array $select * @param int|null $limit * - * @return Generator + * @return Generator|[] * @throws BaseException * @throws Exceptions\TransportException * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface @@ -369,10 +451,15 @@ public function getTraversableListWithoutCount( * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface * @throws \Exception */ - public function getTraversableList(string $apiMethod, array $order, array $filter, array $select, ?int $limit = null): Generator - { - $this->log->debug( - 'getTraversableList.start', + public function getTraversableListWithCount( + string $apiMethod, + array $order, + array $filter, + array $select, + ?int $limit = null + ): Generator { + $this->logger->debug( + 'getTraversableListWithCount.start', [ 'apiMethod' => $apiMethod, 'order' => $order, @@ -397,8 +484,8 @@ public function getTraversableList(string $apiMethod, array $order, array $filte $nextItem = $firstResult->getResponseData()->getPagination()->getNextItem(); $total = $firstResult->getResponseData()->getPagination()->getTotal(); - $this->log->debug( - 'getTraversableList.calculateCommandsRange', + $this->logger->debug( + 'getTraversableListWithCount.calculateCommandsRange', [ 'nextItem' => $nextItem, 'totalItems' => $total, @@ -434,8 +521,8 @@ public function getTraversableList(string $apiMethod, array $order, array $filte ); } - $this->log->debug( - 'getTraversableList.commandsRegistered', + $this->logger->debug( + 'getTraversableListWithCount.commandsRegistered', [ 'commandsCount' => $this->commands->count(), 'totalItemsToSelect' => $total, @@ -448,8 +535,8 @@ public function getTraversableList(string $apiMethod, array $order, array $filte /** * @var $queryResultData ResponseData */ - $this->log->debug( - 'getTraversableList.batchResultItem', + $this->logger->debug( + 'getTraversableListWithCount.batchResultItem', [ 'batchCommandItemNumber' => $queryCnt, 'nextItem' => $queryResultData->getPagination()->getNextItem(), @@ -466,7 +553,7 @@ public function getTraversableList(string $apiMethod, array $order, array $filte } } - $this->log->debug('getTraversableList.finish'); + $this->logger->debug('getTraversableListWithCount.finish'); } /** @@ -483,7 +570,7 @@ public function getTraversableList(string $apiMethod, array $order, array $filte */ protected function getTraversable(bool $isHaltOnError): Generator { - $this->log->debug( + $this->logger->debug( 'getTraversable.start', [ 'isHaltOnError' => $isHaltOnError, @@ -494,7 +581,7 @@ protected function getTraversable(bool $isHaltOnError): Generator /** * @var $batchResult Response */ - $this->log->debug( + $this->logger->debug( 'getTraversable.batchResultItem.processStart', [ 'batchItemNumber' => $batchItem, @@ -537,9 +624,9 @@ protected function getTraversable(bool $isHaltOnError): Generator new Pagination($nextItem, $total) ); } - $this->log->debug('getTraversable.batchResult.processFinish'); + $this->logger->debug('getTraversable.batchResult.processFinish'); } - $this->log->debug('getTraversable.finish'); + $this->logger->debug('getTraversable.finish'); } /** @@ -551,7 +638,7 @@ protected function getTraversable(bool $isHaltOnError): Generator */ private function getTraversableBatchResults(bool $isHaltOnError): Generator { - $this->log->debug( + $this->logger->debug( 'getTraversableBatchResults.start', [ 'commandsCount' => $this->commands->count(), @@ -565,7 +652,7 @@ private function getTraversableBatchResults(bool $isHaltOnError): Generator $batchQueryCounter = 0; while (count($apiCommands)) { $batchQuery = array_splice($apiCommands, 0, self::MAX_BATCH_PACKET_SIZE); - $this->log->debug( + $this->logger->debug( 'getTraversableBatchResults.batchQuery', [ 'batchQueryNumber' => $batchQueryCounter, @@ -579,7 +666,7 @@ private function getTraversableBatchResults(bool $isHaltOnError): Generator $batchQueryCounter++; yield $batchResult; } - $this->log->debug('getTraversableBatchResults.finish'); + $this->logger->debug('getTraversableBatchResults.finish'); } /** diff --git a/src/Core/Contracts/BatchInterface.php b/src/Core/Contracts/BatchInterface.php index a63d7440..5c11d89d 100644 --- a/src/Core/Contracts/BatchInterface.php +++ b/src/Core/Contracts/BatchInterface.php @@ -16,7 +16,7 @@ interface BatchInterface { /** - * batch wrapper for *.list methods + * Batch wrapper for *.list methods without counting elements on every api-call * * @param string $apiMethod * @param array $order @@ -27,7 +27,35 @@ interface BatchInterface * @return Generator * @throws BaseException */ - public function getTraversableList(string $apiMethod, array $order, array $filter, array $select, ?int $limit = null): Generator; + public function getTraversableList( + string $apiMethod, + array $order, + array $filter, + array $select, + ?int $limit = null + ): Generator; + + /** + * Batch wrapper for *.list methods with counting elements on every api-call + * + * ⚠️ Call this wrapper is more expensive than getTraversableList method, use this method carefully + * + * @param string $apiMethod + * @param array $order + * @param array $filter + * @param array $select + * @param int|null $limit + * + * @return Generator + * @throws BaseException + */ + public function getTraversableListWithCount( + string $apiMethod, + array $order, + array $filter, + array $select, + ?int $limit = null + ): Generator; /** * Add entity items with batch call @@ -47,7 +75,9 @@ public function addEntityItems(string $apiMethod, array $entityItems): Generator * @param array $entityItemId * * @return Generator|ResponseData[] - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws BaseException */ public function deleteEntityItems(string $apiMethod, array $entityItemId): Generator; + + //todo add updateEntityItems } \ No newline at end of file From 8d10babffede5aaba5234d8f436bf17b80d0018b Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 5 Feb 2022 11:37:13 +0300 Subject: [PATCH 271/647] add fixes in batch system Signed-off-by: mesilov --- CHANGELOG.md | 3 + src/Core/Batch.php | 20 ++ src/Core/Result/DeletedItemBatchResult.php | 37 +++ src/Core/Result/DeletedItemResult.php | 3 +- src/Services/CRM/Deal/Service/Batch.php | 19 +- tests/Integration/Core/BatchTest.php | 303 +++++++++++++++++- .../Services/CRM/Deal/Service/BatchTest.php | 97 ++++++ .../Services/CRM/Deal/Service/DealTest.php | 33 -- 8 files changed, 464 insertions(+), 51 deletions(-) create mode 100644 src/Core/Result/DeletedItemBatchResult.php create mode 100644 tests/Integration/Services/CRM/Deal/Service/BatchTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index f433a221..01c80204 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ * add «fast» batch-query without counting elements in result recordset [Добавить поддержку выгрузки большого количества данных без подсчёта элементов (-1](https://github.com/mesilov/bitrix24-php-sdk/issues/248) * add method `Core\Batch::deleteEntityItems` for delete items in batch mode and integration test +* add type check in method `Core\Batch::deleteEntityItems` - only integer id allowed +* add interface `Core\Contracts\DeletedItemResultInterface` +* add in scope «CRM» `Services\CRM\Deal\Service\Batch::delete` batch delete deals * add `symfony/stopwatch` component for integration tests * add `/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser` for parse `curl_info` network data structures for debug logs in `Bitrix24\SDK\Core\Response::__destruct()` diff --git a/src/Core/Batch.php b/src/Core/Batch.php index 134b1732..7a408fd0 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -9,6 +9,7 @@ use Bitrix24\SDK\Core\Contracts\BatchInterface; use Bitrix24\SDK\Core\Contracts\CoreInterface; use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; use Bitrix24\SDK\Core\Response\DTO\Pagination; use Bitrix24\SDK\Core\Response\DTO\ResponseData; use Bitrix24\SDK\Core\Response\DTO\Result; @@ -123,12 +124,31 @@ public function deleteEntityItems(string $apiMethod, array $entityItemId): Gener try { $this->clearCommands(); foreach ($entityItemId as $cnt => $itemId) { + if (!is_int($itemId)) { + throw new InvalidArgumentException( + sprintf( + 'invalid type «%s» of entity id «%s» at position %s, entity id must be integer type', + gettype($itemId), + $itemId, + $cnt + ) + ); + } $this->registerCommand($apiMethod, ['ID' => $itemId]); } foreach ($this->getTraversable(true) as $cnt => $deletedItemResult) { yield $cnt => $deletedItemResult; } + } catch (InvalidArgumentException $exception) { + $errorMessage = sprintf('batch delete entity items: %s', $exception->getMessage()); + $this->logger->error( + $errorMessage, + [ + 'trace' => $exception->getTrace(), + ] + ); + throw $exception; } catch (\Throwable $exception) { $errorMessage = sprintf('batch delete entity items: %s', $exception->getMessage()); $this->logger->error( diff --git a/src/Core/Result/DeletedItemBatchResult.php b/src/Core/Result/DeletedItemBatchResult.php new file mode 100644 index 00000000..f8efe47b --- /dev/null +++ b/src/Core/Result/DeletedItemBatchResult.php @@ -0,0 +1,37 @@ +responseData = $responseData; + } + + /** + * @return \Bitrix24\SDK\Core\Response\DTO\ResponseData + */ + public function getResponseData(): ResponseData + { + return $this->responseData; + } + + /** + * @return bool + */ + public function isSuccess(): bool + { + return (bool)$this->getResponseData()->getResult()->getResultData()[0]; + } +} \ No newline at end of file diff --git a/src/Core/Result/DeletedItemResult.php b/src/Core/Result/DeletedItemResult.php index 5ea0e838..3770582e 100644 --- a/src/Core/Result/DeletedItemResult.php +++ b/src/Core/Result/DeletedItemResult.php @@ -4,6 +4,7 @@ namespace Bitrix24\SDK\Core\Result; +use Bitrix24\SDK\Core\Contracts\DeletedItemResultInterface; use Bitrix24\SDK\Core\Exceptions\BaseException; /** @@ -11,7 +12,7 @@ * * @package Bitrix24\SDK\Core\Result */ -class DeletedItemResult extends AbstractResult +class DeletedItemResult extends AbstractResult implements DeletedItemResultInterface { /** * @return bool diff --git a/src/Services/CRM/Deal/Service/Batch.php b/src/Services/CRM/Deal/Service/Batch.php index 9ba2dc9e..c95df537 100644 --- a/src/Services/CRM/Deal/Service/Batch.php +++ b/src/Services/CRM/Deal/Service/Batch.php @@ -7,6 +7,7 @@ use Bitrix24\SDK\Core\Contracts\BatchInterface; use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Result\AddedItemBatchResult; +use Bitrix24\SDK\Core\Result\DeletedItemBatchResult; use Bitrix24\SDK\Services\CRM\Deal\Result\DealItemResult; use Generator; use Psr\Log\LoggerInterface; @@ -34,7 +35,7 @@ public function __construct(BatchInterface $batch, LoggerInterface $log) } /** - * batch list method for deals + * Batch list method for deals * * @param array{ * ID?: int, @@ -193,6 +194,7 @@ public function list(array $order, array $filter, array $select, ?int $limit = n * }> $deals * * @return Generator|AddedItemBatchResult[] + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException */ public function add(array $deals): Generator { @@ -206,4 +208,19 @@ public function add(array $deals): Generator yield $key => new AddedItemBatchResult($item); } } + + /** + * Batch delete deals + * + * @param int[] $dealId + * + * @return \Generator|\Bitrix24\SDK\Core\Contracts\DeletedItemResultInterface[] + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function delete(array $dealId): Generator + { + foreach ($this->batch->deleteEntityItems('crm.deal.delete', $dealId) as $key => $item) { + yield $key => new DeletedItemBatchResult($item); + } + } } \ No newline at end of file diff --git a/tests/Integration/Core/BatchTest.php b/tests/Integration/Core/BatchTest.php index 77ab0c86..b77a9446 100644 --- a/tests/Integration/Core/BatchTest.php +++ b/tests/Integration/Core/BatchTest.php @@ -5,15 +5,272 @@ namespace Bitrix24\SDK\Tests\Integration\Core; use Bitrix24\SDK\Core\Batch; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; use Bitrix24\SDK\Services\ServiceBuilder; use Bitrix24\SDK\Tests\Integration\Fabric; use PHPUnit\Framework\TestCase; +use Symfony\Component\Stopwatch\Stopwatch; class BatchTest extends TestCase { - protected Batch $batchService; - protected ServiceBuilder $serviceBuilder; - private const DEMO_DATA_ARRAY_SIZE = 125; + private Batch $batch; + private ServiceBuilder $serviceBuilder; + private Stopwatch $stopwatch; + private const DEMO_DATA_ARRAY_SIZE_LESS_THAN_PAGE = 35; + private const DEMO_DATA_ARRAY_SIZE_MORE_THAN_ONE_PAGE_SIZE = 65; + private const DEMO_DATA_ARRAY_SIZE_MORE_THAN_MAX_BATCH_PAGE_COUNT = 2735; + private const LIMIT_ELEMENTS_IN_RESULT = 10; + + /** + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Exception + * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + * @covers \Bitrix24\SDK\Core\Batch::getTraversableList + * @testdox Get traversable list items in batch mode with more than max batch page count elements + */ + public function testGetTraversableListWithMoreThanMaxBatchPageCountWithoutLimit(): void + { + // prepare demo data + $contactId = $this->serviceBuilder->getCRMScope()->contact()->add( + [ + 'NAME' => sprintf('first_%s', time()), + 'SECOND' => sprintf('second_%s', time()), + ] + )->getId(); + + // add deals to bitrix24 + $rawDeals = []; + for ($i = 0; $i < self::DEMO_DATA_ARRAY_SIZE_MORE_THAN_MAX_BATCH_PAGE_COUNT; $i++) { + $rawDeals[] = [ + 'TITLE' => sprintf('deal-%s', $i), + 'IS_MANUAL_OPPORTUNITY' => 'Y', + 'OPPORTUNITY' => sprintf('%s.00', random_int(100, 40000)), + 'CURRENCY_ID' => 'RUB', + 'CONTACT_ID' => $contactId, + ]; + } + $dealIdList = []; + foreach ($this->serviceBuilder->getCRMScope()->deal()->batch->add($rawDeals) as $addDealResult) { + $dealIdList[] = $addDealResult->getId(); + } + $this->assertCount(self::DEMO_DATA_ARRAY_SIZE_MORE_THAN_MAX_BATCH_PAGE_COUNT, $dealIdList); + + + // count added deals by default deal service + $filter = [ + 'CONTACT_ID' => $contactId, + ]; + + $elementsCountByFilter = $this->serviceBuilder->getCRMScope()->deal()->countByFilter($filter); + $this->assertEquals(self::DEMO_DATA_ARRAY_SIZE_MORE_THAN_MAX_BATCH_PAGE_COUNT, $elementsCountByFilter); + + $select = [ + '*', + ]; + + $dealIdListFromBatch = []; + $batchElementsCount = 0; + $this->stopwatch->start('getTraversableList'); + foreach ($this->batch->getTraversableList('crm.deal.list', [], $filter, $select) as $cnt => $dealItem) { + $batchElementsCount++; + $dealIdListFromBatch[] = $dealItem['ID']; + print(sprintf( + '%s-%s| %s | %s - %s', + $cnt, + self::DEMO_DATA_ARRAY_SIZE_MORE_THAN_MAX_BATCH_PAGE_COUNT, + $dealItem['ID'], + $dealItem['TITLE'], + $dealItem['OPPORTUNITY'], + ) . PHP_EOL); + } + $this->stopwatch->stop('getTraversableList'); + $this->assertEquals( + self::DEMO_DATA_ARRAY_SIZE_MORE_THAN_MAX_BATCH_PAGE_COUNT, + $batchElementsCount, + sprintf( + 'elements count by filter %s not equals elements count from batch getTraversableList %s', + $elementsCountByFilter, + $batchElementsCount + ) + ); + $this->assertEquals($dealIdList, $dealIdListFromBatch, sprintf('added deal id array doesnt not equals array in batch result list')); + + print(sprintf( + 'getTraversableList timing - %s ms | %s sec' . PHP_EOL, + $this->stopwatch->getEvent('getTraversableList')->getDuration(), + $this->stopwatch->getEvent('getTraversableList')->getDuration() / 1000 + )); + + //try to delete deals + $deletedItemsCount = 0; + foreach ($this->batch->deleteEntityItems('crm.deal.delete', $dealIdList) as $cnt => $deletedResult) { + $deletedItemsCount++; + } + $this->assertEquals( + self::DEMO_DATA_ARRAY_SIZE_MORE_THAN_MAX_BATCH_PAGE_COUNT, + $deletedItemsCount, + sprintf( + 'elements count by filter %s not equals deleted elements count from batch deleteEntityItems %s', + $elementsCountByFilter, + $deletedItemsCount + ) + ); + } + + /** + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Exception + * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + * @covers \Bitrix24\SDK\Core\Batch::getTraversableList + * @testdox Get traversable list items in batch mode with less than one page with limit elements + */ + public function testGetTraversableListWithLessThanPageSizeWithLimit(): void + { + // prepare demo data + $contactId = $this->serviceBuilder->getCRMScope()->contact()->add( + [ + 'NAME' => sprintf('first_%s', time()), + 'SECOND' => sprintf('second_%s', time()), + ] + )->getId(); + + // add deals to bitrix24 + $rawDeals = []; + for ($i = 0; $i < self::DEMO_DATA_ARRAY_SIZE_LESS_THAN_PAGE; $i++) { + $rawDeals[] = [ + 'TITLE' => sprintf('deal-%s', $i), + 'IS_MANUAL_OPPORTUNITY' => 'Y', + 'OPPORTUNITY' => sprintf('%s.00', random_int(100, 40000)), + 'CURRENCY_ID' => 'RUB', + 'CONTACT_ID' => $contactId, + ]; + } + $dealIdList = []; + foreach ($this->serviceBuilder->getCRMScope()->deal()->batch->add($rawDeals) as $addDealResult) { + $dealIdList[] = $addDealResult->getId(); + } + $this->assertCount(self::DEMO_DATA_ARRAY_SIZE_LESS_THAN_PAGE, $dealIdList); + + + // count added deals by default deal service + $filter = [ + 'CONTACT_ID' => $contactId, + ]; + + $elementsCountByFilter = $this->serviceBuilder->getCRMScope()->deal()->countByFilter($filter); + $this->assertEquals(self::DEMO_DATA_ARRAY_SIZE_LESS_THAN_PAGE, $elementsCountByFilter); + + $select = [ + 'ID', + 'TITLE', + 'OPPORTUNITY', + ]; + + $limitElements = self::LIMIT_ELEMENTS_IN_RESULT; + $batchElementsCount = 0; + $this->stopwatch->start('getTraversableList'); + foreach ($this->batch->getTraversableList('crm.deal.list', [], $filter, $select, $limitElements) as $cnt => $dealItem) { + $batchElementsCount++; + print(sprintf( + '%s-%s| %s | %s - %s', + $cnt, + $limitElements, + $dealItem['ID'], + $dealItem['TITLE'], + $dealItem['OPPORTUNITY'], + ) . PHP_EOL); + } + $this->stopwatch->stop('getTraversableList'); + $this->assertEquals( + $limitElements, + $batchElementsCount, + sprintf( + 'elements count by filter %s not equals elements count from batch getTraversableList %s', + $limitElements, + $batchElementsCount + ) + ); + } + + /** + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Exception + * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + * @covers \Bitrix24\SDK\Core\Batch::getTraversableList + * @testdox Get traversable list items in batch mode with count more than one page without limit + */ + public function testGetTraversableListWithLessThanPageSizeWithoutLimit(): void + { + // prepare demo data + $contactId = $this->serviceBuilder->getCRMScope()->contact()->add( + [ + 'NAME' => sprintf('first_%s', time()), + 'SECOND' => sprintf('second_%s', time()), + ] + )->getId(); + + // add deals to bitrix24 + $rawDeals = []; + for ($i = 0; $i < self::DEMO_DATA_ARRAY_SIZE_LESS_THAN_PAGE; $i++) { + $rawDeals[] = [ + 'TITLE' => sprintf('deal-%s', $i), + 'IS_MANUAL_OPPORTUNITY' => 'Y', + 'OPPORTUNITY' => sprintf('%s.00', random_int(100, 40000)), + 'CURRENCY_ID' => 'RUB', + 'CONTACT_ID' => $contactId, + ]; + } + $dealIdList = []; + foreach ($this->serviceBuilder->getCRMScope()->deal()->batch->add($rawDeals) as $addDealResult) { + $dealIdList[] = $addDealResult->getId(); + } + $this->assertCount(self::DEMO_DATA_ARRAY_SIZE_LESS_THAN_PAGE, $dealIdList); + + + // count added deals by default deal service + $filter = [ + 'CONTACT_ID' => $contactId, + ]; + + $elementsCountByFilter = $this->serviceBuilder->getCRMScope()->deal()->countByFilter($filter); + $this->assertEquals(self::DEMO_DATA_ARRAY_SIZE_LESS_THAN_PAGE, $elementsCountByFilter); + + $select = [ + 'ID', + 'TITLE', + 'OPPORTUNITY', + ]; + + $batchElementsCount = 0; + $this->stopwatch->start('getTraversableList'); + foreach ($this->batch->getTraversableList('crm.deal.list', [], $filter, $select) as $cnt => $dealItem) { + $batchElementsCount++; + print(sprintf( + '%s-%s| %s | %s - %s', + $cnt, + $elementsCountByFilter, + $dealItem['ID'], + $dealItem['TITLE'], + $dealItem['OPPORTUNITY'], + ) . PHP_EOL); + } + $this->stopwatch->stop('getTraversableList'); + $this->assertEquals( + $elementsCountByFilter, + $batchElementsCount, + sprintf( + 'elements count by filter %s not equals elements count from batch getTraversableList %s', + $elementsCountByFilter, + $batchElementsCount + ) + ); + } /** * @return void @@ -21,9 +278,9 @@ class BatchTest extends TestCase * @throws \Bitrix24\SDK\Core\Exceptions\TransportException * @throws \Exception * @covers \Bitrix24\SDK\Core\Batch::addEntityItems - * @testdox Добавление сущностей в batch режиме + * @testdox Add items in batch mode */ - public function testBatchAddCommand(): void + public function testBatchAddEntityItems(): void { // prepare demo data $contactId = $this->serviceBuilder->getCRMScope()->contact()->add( @@ -33,7 +290,7 @@ public function testBatchAddCommand(): void ] )->getId(); $rawDeals = []; - for ($i = 0; $i < self::DEMO_DATA_ARRAY_SIZE; $i++) { + for ($i = 0; $i < self::DEMO_DATA_ARRAY_SIZE_LESS_THAN_PAGE; $i++) { $rawDeals[] = [ [ 'fields' => [ @@ -47,10 +304,10 @@ public function testBatchAddCommand(): void // add deals to bitrix24 $dealIdList = []; - foreach ($this->batchService->addEntityItems('crm.deal.add', $rawDeals) as $cnt => $addDealResult) { + foreach ($this->batch->addEntityItems('crm.deal.add', $rawDeals) as $cnt => $addDealResult) { $dealIdList[] = $addDealResult->getResult()->getResultData()[0]; } - $this->assertCount(self::DEMO_DATA_ARRAY_SIZE, $dealIdList); + $this->assertCount(self::DEMO_DATA_ARRAY_SIZE_LESS_THAN_PAGE, $dealIdList); } /** @@ -60,9 +317,9 @@ public function testBatchAddCommand(): void * @throws \Exception * @covers \Bitrix24\SDK\Core\Batch::addEntityItems * @covers \Bitrix24\SDK\Core\Batch::deleteEntityItems - * @testdox Удаление сущностей в batch режиме + * @testdox Delete items in batch mode */ - public function testBatchDeleteCommand(): void + public function testBatchDeleteEntityItems(): void { // prepare demo data $contactId = $this->serviceBuilder->getCRMScope()->contact()->add( @@ -72,7 +329,7 @@ public function testBatchDeleteCommand(): void ] )->getId(); $rawDeals = []; - for ($i = 0; $i < self::DEMO_DATA_ARRAY_SIZE; $i++) { + for ($i = 0; $i < self::DEMO_DATA_ARRAY_SIZE_LESS_THAN_PAGE; $i++) { $rawDeals[] = [ [ 'fields' => [ @@ -86,22 +343,36 @@ public function testBatchDeleteCommand(): void // add deals to bitrix24 $dealIdList = []; - foreach ($this->batchService->addEntityItems('crm.deal.add', $rawDeals) as $cnt => $addDealResult) { + foreach ($this->batch->addEntityItems('crm.deal.add', $rawDeals) as $cnt => $addDealResult) { $dealIdList[] = $addDealResult->getResult()->getResultData()[0]; } - $this->assertCount(self::DEMO_DATA_ARRAY_SIZE, $dealIdList); + $this->assertCount(self::DEMO_DATA_ARRAY_SIZE_LESS_THAN_PAGE, $dealIdList); // delete deals from bitrix24 $dealsDeleteResult = []; - foreach ($this->batchService->deleteEntityItems('crm.deal.delete', $dealIdList) as $cnt => $deleteDealResult) { + foreach ($this->batch->deleteEntityItems('crm.deal.delete', $dealIdList) as $cnt => $deleteDealResult) { + $dealsDeleteResult[] = $deleteDealResult->getResult()->getResultData()[0]; + } + $this->assertCount(self::DEMO_DATA_ARRAY_SIZE_LESS_THAN_PAGE, $dealsDeleteResult); + } + + /** + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @testdox Delete items in batch mode with wrong type of entity id + */ + public function testBatchDeleteEntityItemsWithWrongTypeOfEntityId(): void + { + $this->expectException(InvalidArgumentException::class); + foreach ($this->batch->deleteEntityItems('crm.deal.delete', [1, 2, '3', 4, 5]) as $cnt => $deleteDealResult) { $dealsDeleteResult[] = $deleteDealResult->getResult()->getResultData()[0]; } - $this->assertCount(self::DEMO_DATA_ARRAY_SIZE, $dealsDeleteResult); } public function setUp(): void { - $this->batchService = Fabric::getBatchService(); + $this->stopwatch = new Stopwatch(true); + $this->batch = Fabric::getBatchService(); $this->serviceBuilder = Fabric::getServiceBuilder(); } diff --git a/tests/Integration/Services/CRM/Deal/Service/BatchTest.php b/tests/Integration/Services/CRM/Deal/Service/BatchTest.php new file mode 100644 index 00000000..f50524bb --- /dev/null +++ b/tests/Integration/Services/CRM/Deal/Service/BatchTest.php @@ -0,0 +1,97 @@ +dealService->add(['TITLE' => 'test deal'])->getId(); + $cnt = 0; + + foreach ($this->dealService->batch->list([], ['ID' => $dealId], ['ID', 'NAME'], 1) as $item) { + $cnt++; + } + self::assertGreaterThanOrEqual(1, $cnt); + + $this->dealService->delete($dealId); + } + + /** + * @testdox Batch add deals + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\Batch::add() + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function testBatchAdd(): void + { + $deals = []; + for ($i = 1; $i < 60; $i++) { + $deals[] = ['TITLE' => 'TITLE-' . $i]; + } + $cnt = 0; + $dealId = []; + foreach ($this->dealService->batch->add($deals) as $item) { + $cnt++; + $dealId[] = $item->getId(); + } + self::assertEquals(count($deals), $cnt); + + $cnt = 0; + foreach ($this->dealService->batch->delete($dealId) as $cnt => $deleteResult) { + $cnt++; + } + self::assertEquals(count($deals), $cnt); + } + + /** + * @testdox Batch delete deals + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\Batch::add() + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function testBatchDelete(): void + { + $deals = []; + for ($i = 1; $i < 60; $i++) { + $deals[] = ['TITLE' => 'TITLE-' . $i]; + } + $cnt = 0; + $dealId = []; + foreach ($this->dealService->batch->add($deals) as $item) { + $cnt++; + $dealId[] = $item->getId(); + } + self::assertEquals(count($deals), $cnt); + + $cnt = 0; + foreach ($this->dealService->batch->delete($dealId) as $cnt => $deleteResult) { + $cnt++; + } + self::assertEquals(count($deals), $cnt); + } + + public function setUp(): void + { + $this->dealService = Fabric::getServiceBuilder()->getCRMScope()->deal(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Deal/Service/DealTest.php b/tests/Integration/Services/CRM/Deal/Service/DealTest.php index fc9b853c..527e32a8 100644 --- a/tests/Integration/Services/CRM/Deal/Service/DealTest.php +++ b/tests/Integration/Services/CRM/Deal/Service/DealTest.php @@ -82,39 +82,6 @@ public function testUpdate(): void self::assertEquals($newTitle, $this->dealService->get($deal->getId())->deal()->TITLE); } - /** - * @covers \Bitrix24\SDK\Services\CRM\Contact\Service\Batch::list() - * @throws BaseException - * @throws TransportException - */ - public function testBatchList(): void - { - $this->dealService->add(['TITLE' => 'test deal']); - $cnt = 0; - - foreach ($this->dealService->batch->list([], ['>ID' => '1'], ['ID', 'NAME'], 1) as $item) { - $cnt++; - } - self::assertGreaterThanOrEqual(1, $cnt); - } - - /** - * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\Batch::add() - */ - public function testBatchAdd(): void - { - $deals = []; - for ($i = 1; $i < 60; $i++) { - $deals[] = ['TITLE' => 'TITLE-' . $i]; - } - $cnt = 0; - foreach ($this->dealService->batch->add($deals) as $item) { - $cnt++; - } - - self::assertEquals(count($deals), $cnt); - } - /** * @throws \Bitrix24\SDK\Core\Exceptions\BaseException * @throws \Bitrix24\SDK\Core\Exceptions\TransportException From d9e60a5ab2d9c324ce01dfc91d0dc15638db4a67 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 5 Feb 2022 11:37:36 +0300 Subject: [PATCH 272/647] add DeletedItemResultInterface Signed-off-by: mesilov --- src/Core/Contracts/DeletedItemResultInterface.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/Core/Contracts/DeletedItemResultInterface.php diff --git a/src/Core/Contracts/DeletedItemResultInterface.php b/src/Core/Contracts/DeletedItemResultInterface.php new file mode 100644 index 00000000..8241f02e --- /dev/null +++ b/src/Core/Contracts/DeletedItemResultInterface.php @@ -0,0 +1,15 @@ + Date: Sat, 5 Feb 2022 12:32:15 +0300 Subject: [PATCH 273/647] fix phpstan typecheck errors on level 5 Signed-off-by: mesilov --- src/Core/ApiClient.php | 4 +- src/Core/ApiLevelErrorHandler.php | 2 +- src/Core/Batch.php | 55 +++++++++++----------- src/Core/Contracts/BatchInterface.php | 12 ++--- src/Services/CRM/Contact/Service/Batch.php | 6 +-- src/Services/CRM/Deal/Service/Batch.php | 4 +- src/Services/CRM/Product/Service/Batch.php | 2 +- 7 files changed, 42 insertions(+), 43 deletions(-) diff --git a/src/Core/ApiClient.php b/src/Core/ApiClient.php index 596b2511..901ec5e0 100644 --- a/src/Core/ApiClient.php +++ b/src/Core/ApiClient.php @@ -48,7 +48,7 @@ public function __construct(Credentials\Credentials $credentials, HttpClientInte } /** - * @return array + * @return array */ protected function getDefaultHeaders(): array { @@ -113,7 +113,7 @@ public function getNewAccessToken(): RenewedAccessToken /** * @param string $apiMethod - * @param array $parameters + * @param array $parameters * * @return ResponseInterface * @throws TransportExceptionInterface diff --git a/src/Core/ApiLevelErrorHandler.php b/src/Core/ApiLevelErrorHandler.php index 238ed730..685b9331 100644 --- a/src/Core/ApiLevelErrorHandler.php +++ b/src/Core/ApiLevelErrorHandler.php @@ -33,7 +33,7 @@ public function __construct(LoggerInterface $logger) } /** - * @param array $responseBody + * @param array $responseBody * * @throws QueryLimitExceededException * @throws BaseException diff --git a/src/Core/Batch.php b/src/Core/Batch.php index 7a408fd0..9f8e640d 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -63,7 +63,7 @@ protected function clearCommands(): void * Add entity items with batch call * * @param string $apiMethod - * @param array $entityItems + * @param array $entityItems * * @return Generator|ResponseData[] * @throws BaseException @@ -167,10 +167,10 @@ public function deleteEntityItems(string $apiMethod, array $entityItemId): Gener /** * 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 + * @param string $apiMethod + * @param array $parameters + * @param string|null $commandName + * @param callable|null $callback not implemented * * @throws \Exception */ @@ -200,7 +200,7 @@ protected function registerCommand( } /** - * @param array $order + * @param array $order * * @return array|string[] */ @@ -240,20 +240,19 @@ 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 + * @param string $apiMethod + * @param array $order + * @param array $filter + * @param array $select + * @param int|null $limit * - * @return Generator - * @throws BaseException - * @throws Exceptions\TransportException + * @return \Generator + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface - * @throws \Exception */ public function getTraversableList( string $apiMethod, @@ -421,12 +420,12 @@ public function getTraversableList( } /** - * @param int $startElementId - * @param int $lastElementId - * @param bool $isLastPage - * @param array $oldFilter + * @param int $startElementId + * @param int $lastElementId + * @param bool $isLastPage + * @param array $oldFilter * - * @return array + * @return array */ protected function updateFilterForBatch(int $startElementId, int $lastElementId, bool $isLastPage, array $oldFilter): array { @@ -456,13 +455,13 @@ protected function updateFilterForBatch(int $startElementId, int $lastElementId, * * work with start item position and elements count * - * @param string $apiMethod - * @param array $order - * @param array $filter - * @param array $select - * @param int|null $limit + * @param string $apiMethod + * @param array $order + * @param array $filter + * @param array $select + * @param int|null $limit * - * @return Generator|[] + * @return Generator * @throws BaseException * @throws Exceptions\TransportException * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface @@ -652,7 +651,7 @@ protected function getTraversable(bool $isHaltOnError): Generator /** * @param bool $isHaltOnError * - * @return Generator + * @return Generator * @throws BaseException * @throws Exceptions\TransportException */ @@ -690,7 +689,7 @@ private function getTraversableBatchResults(bool $isHaltOnError): Generator } /** - * @return array + * @return array */ private function convertToApiCommands(): array { diff --git a/src/Core/Contracts/BatchInterface.php b/src/Core/Contracts/BatchInterface.php index 5c11d89d..d259a9d2 100644 --- a/src/Core/Contracts/BatchInterface.php +++ b/src/Core/Contracts/BatchInterface.php @@ -18,13 +18,13 @@ interface BatchInterface /** * Batch wrapper for *.list methods without counting elements on every api-call * - * @param string $apiMethod - * @param array $order - * @param array $filter - * @param array $select - * @param int|null $limit + * @param string $apiMethod + * @param array $order + * @param array $filter + * @param array $select + * @param int|null $limit * - * @return Generator + * @return Generator * @throws BaseException */ public function getTraversableList( diff --git a/src/Services/CRM/Contact/Service/Batch.php b/src/Services/CRM/Contact/Service/Batch.php index 2271b8ac..55172488 100644 --- a/src/Services/CRM/Contact/Service/Batch.php +++ b/src/Services/CRM/Contact/Service/Batch.php @@ -21,7 +21,7 @@ class Batch extends AbstractBatchService * batch list method * * @param array{ - * ID?: int, + * ID?: string, * HONORIFIC?: string, * NAME?: string, * SECOND_NAME?: string, @@ -40,7 +40,7 @@ class Batch extends AbstractBatchService * ADDRESS_PROVINCE?: string, * ADDRESS_COUNTRY?: string, * ADDRESS_COUNTRY_CODE?: string, - * ADDRESS_LOC_ADDR_ID?: int, + * ADDRESS_LOC_ADDR_ID?: string, * COMMENTS?: string, * OPENED?: string, * EXPORT?: string, @@ -58,7 +58,7 @@ class Batch extends AbstractBatchService * ORIGINATOR_ID?: string, * ORIGIN_ID?: string, * ORIGIN_VERSION?: string, - * FACE_ID?: int, + * FACE_ID?: string, * UTM_SOURCE?: string, * UTM_MEDIUM?: string, * UTM_CAMPAIGN?: string, diff --git a/src/Services/CRM/Deal/Service/Batch.php b/src/Services/CRM/Deal/Service/Batch.php index c95df537..81113517 100644 --- a/src/Services/CRM/Deal/Service/Batch.php +++ b/src/Services/CRM/Deal/Service/Batch.php @@ -38,7 +38,7 @@ public function __construct(BatchInterface $batch, LoggerInterface $log) * Batch list method for deals * * @param array{ - * ID?: int, + * ID?: string, * TITLE?: string, * TYPE_ID?: string, * CATEGORY_ID?: string, @@ -48,7 +48,7 @@ public function __construct(BatchInterface $batch, LoggerInterface $log) * IS_RECURRING?: string, * IS_RETURN_CUSTOMER?: string, * IS_REPEATED_APPROACH?: string, - * PROBABILITY?: int, + * PROBABILITY?: string, * CURRENCY_ID?: string, * OPPORTUNITY?: string, * IS_MANUAL_OPPORTUNITY?: string, diff --git a/src/Services/CRM/Product/Service/Batch.php b/src/Services/CRM/Product/Service/Batch.php index ee553c60..5858aece 100644 --- a/src/Services/CRM/Product/Service/Batch.php +++ b/src/Services/CRM/Product/Service/Batch.php @@ -21,7 +21,7 @@ class Batch extends AbstractBatchService * batch list method * * @param array{ - * ID?: int + * ID?: string * } $order * * @param array{ From 9012764a8f66d2abc5fd1c99e765dc7dabb20d41 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 5 Feb 2022 12:32:32 +0300 Subject: [PATCH 274/647] add memory limit to phpstan Signed-off-by: mesilov --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 7c92ae9d..571dec6c 100644 --- a/composer.json +++ b/composer.json @@ -56,7 +56,7 @@ "phpunit --testsuite integration_tests" ], "phpstan-analyse": [ - "vendor/bin/phpstan analyse" + "vendor/bin/phpstan analyse --memory-limit 1G" ] } } \ No newline at end of file From 3e7a95e9f0de93329cae0092e97bec3d2ecf24ec Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 5 Feb 2022 12:41:20 +0300 Subject: [PATCH 275/647] add phpstan github action bage Signed-off-by: mesilov --- README.md | 45 ++++++++++++++++++++++++++++----------------- phpstan.neon.dist | 1 - 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index fc42448b..d1145d31 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,13 @@ -bitrix24-php-sdk [![Build Status](https://travis-ci.org/mesilov/bitrix24-php-sdk.svg?branch=master)](https://travis-ci.org/mesilov/bitrix24-php-sdk) +bitrix24-php-sdk – PHP7.4|8.x Bitrix24 REST API SDK ================ [![License](https://poser.pugx.org/mesilov/bitrix24-php-sdk/license.svg)](https://packagist.org/packages/mesilov/bitrix24-php-sdk) [![Total Downloads](https://poser.pugx.org/mesilov/bitrix24-php-sdk/downloads.svg)](https://packagist.org/packages/mesilov/bitrix24-php-sdk) A powerful PHP library for the Bitrix24 REST API + +### Build status + +![phpstan check](https://github.com/mesilov/bitrix24-php-sdk/actions/workflows/phpstan.yml/badge.svg) + ### BITRIX24-PHP-SDK Documentation - [Russian](/docs/RU/documentation.md) @@ -42,23 +47,23 @@ Performance improvements 🚀 ### Development principles - Good developer experience - - auto-completion of methods at the IDE - - typed method call signatures - - typed results of method calls - - helpers for typical operations + - auto-completion of methods at the IDE + - typed method call signatures + - typed results of method calls + - helpers for typical operations - Good documentation - - documentation on the operation of a specific method containing a link to the official documentation - - documentation for working with the SDK + - documentation on the operation of a specific method containing a link to the official documentation + - documentation for working with the SDK - Performance first: - - minimal impact on client code - - ability to work with large amounts of data with constant memory consumption - - efficient operation of the API using butch requests + - minimal impact on client code + - ability to work with large amounts of data with constant memory consumption + - efficient operation of the API using butch requests - Modern technology stack - - based on [Symfony HttpClient](https://symfony.com/doc/current/http_client.html) - - actual PHP versions language features + - based on [Symfony HttpClient](https://symfony.com/doc/current/http_client.html) + - actual PHP versions language features - Reliable: - - test coverage: unit, integration, contract - - typical examples typical for different modes of operation and they are optimized for memory \ performance + - test coverage: unit, integration, contract + - typical examples typical for different modes of operation and they are optimized for memory \ performance ### Architecture @@ -107,22 +112,25 @@ Performance improvements 🚀 Add `"mesilov/bitrix24-php-sdk": "2.x"` to `composer.json` of your application. Or clone repo to your project. ### Tests + Tests locate in folder `tests` and we have two test types #### Unit tests -**Fast**, in-memory tests without a network I\O -For run unit tests you must call in command line + +**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 ``` #### Integration tests + **Slow** tests with full lifecycle with your **test** Bitrix24 portal via webhook. ❗️Do not run integration tests with production portals ❗️ For run integration test you must: + 1. Create [new Bitrix24 portal](https://www.bitrix24.ru/create.php?p=255670) for development tests 2. Go to left menu, click «Sitemap» 3. Find menu item «Developer resources» @@ -130,11 +138,13 @@ For run integration test you must: 5. Click on menu item «Inbound webhook» 6. Assign all permisions with webhook and click «save» button 7. Create file `/tests/.env.local` with same settings, see comments in `/tests/.env` file. + ```yaml APP_ENV=dev BITRIX24_WEBHOOK=https:// your portal webhook url INTEGRATION_TEST_LOG_LEVEL=500 ``` + 8. call in command line ```shell @@ -142,12 +152,13 @@ composer composer phpunit-run-integration-tests ``` #### PHP Static Analysis Tool – phpstan + Call in command line + ```shell composer phpstan-analyse ``` - ### Submitting bugs and feature requests Bugs and feature request are tracked on [GitHub](https://github.com/mesilov/bitrix24-php-sdk/issues) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 6856bc7f..7e4f8de6 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -2,6 +2,5 @@ parameters: level: 5 paths: - src/ -# - tests/ bootstrapFiles: - tests/bootstrap.php \ No newline at end of file From fb8efc5abcbe12a75a4e540f181e8052e37a1ad6 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 5 Feb 2022 12:49:27 +0300 Subject: [PATCH 276/647] update readme Signed-off-by: mesilov --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d1145d31..b9eed4c9 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ -bitrix24-php-sdk – PHP7.4|8.x Bitrix24 REST API SDK +bitrix24-php-sdk – Bitrix24 REST API PHP SDK ================ [![License](https://poser.pugx.org/mesilov/bitrix24-php-sdk/license.svg)](https://packagist.org/packages/mesilov/bitrix24-php-sdk) [![Total Downloads](https://poser.pugx.org/mesilov/bitrix24-php-sdk/downloads.svg)](https://packagist.org/packages/mesilov/bitrix24-php-sdk) - +[![Latest Stable Version](https://img.shields.io/packagist/v/mesilov/bitrix24-php-sdk.svg)](https://packagist.org/packages/mesilov/bitrix24-php-sdk) A powerful PHP library for the Bitrix24 REST API ### Build status -![phpstan check](https://github.com/mesilov/bitrix24-php-sdk/actions/workflows/phpstan.yml/badge.svg) +[![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) ### BITRIX24-PHP-SDK Documentation From b3ba42b6dc48d2a129fc2744c1f3616032f58ac3 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 5 Feb 2022 12:51:55 +0300 Subject: [PATCH 277/647] update readme build status Signed-off-by: mesilov --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index b9eed4c9..3ef6188e 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,13 @@ bitrix24-php-sdk – Bitrix24 REST API PHP SDK ================ [![License](https://poser.pugx.org/mesilov/bitrix24-php-sdk/license.svg)](https://packagist.org/packages/mesilov/bitrix24-php-sdk) [![Total Downloads](https://poser.pugx.org/mesilov/bitrix24-php-sdk/downloads.svg)](https://packagist.org/packages/mesilov/bitrix24-php-sdk) [![Latest Stable Version](https://img.shields.io/packagist/v/mesilov/bitrix24-php-sdk.svg)](https://packagist.org/packages/mesilov/bitrix24-php-sdk) + A powerful PHP library for the Bitrix24 REST API ### Build status [![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) +[![phpunit 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) ### BITRIX24-PHP-SDK Documentation From 4daed6f542e8cbd748cd29098aa1123709f3d0f8 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 5 Feb 2022 18:21:04 +0300 Subject: [PATCH 278/647] add integration test for FilterWithBatchWithoutCountOrderTest Signed-off-by: mesilov --- CHANGELOG.md | 1 + src/Core/ApiClient.php | 10 +- .../FilterWithBatchWithoutCountOrderTest.php | 120 ++++++++++++++++++ 3 files changed, 127 insertions(+), 4 deletions(-) create mode 100644 tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrderTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 01c80204..17153ef5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ * add «fast» batch-query without counting elements in result recordset [Добавить поддержку выгрузки большого количества данных без подсчёта элементов (-1](https://github.com/mesilov/bitrix24-php-sdk/issues/248) * add method `Core\Batch::deleteEntityItems` for delete items in batch mode and integration test +* add integration test for read strategy `FilterWithBatchWithoutCountOrderTest` * add type check in method `Core\Batch::deleteEntityItems` - only integer id allowed * add interface `Core\Contracts\DeletedItemResultInterface` * add in scope «CRM» `Services\CRM\Deal\Service\Batch::delete` batch delete deals diff --git a/src/Core/ApiClient.php b/src/Core/ApiClient.php index 901ec5e0..b637a71c 100644 --- a/src/Core/ApiClient.php +++ b/src/Core/ApiClient.php @@ -112,8 +112,8 @@ public function getNewAccessToken(): RenewedAccessToken } /** - * @param string $apiMethod - * @param array $parameters + * @param string $apiMethod + * @param array $parameters * * @return ResponseInterface * @throws TransportExceptionInterface @@ -122,8 +122,9 @@ public function getNewAccessToken(): RenewedAccessToken public function getResponse(string $apiMethod, array $parameters = []): ResponseInterface { $this->logger->info( - sprintf('getResponse.start %s', $apiMethod), + 'getResponse.start', [ + 'apiMethod' => $apiMethod, 'domainUrl' => $this->credentials->getDomainUrl(), 'parameters' => $parameters, ] @@ -148,8 +149,9 @@ public function getResponse(string $apiMethod, array $parameters = []): Response $response = $this->client->request($method, $url, $requestOptions); $this->logger->info( - sprintf('getResponse.end [%s]', $apiMethod), + 'getResponse.end', [ + 'apiMethod' => $apiMethod, 'responseInfo' => $response->getInfo(), ] ); diff --git a/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrderTest.php b/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrderTest.php new file mode 100644 index 00000000..d64a599f --- /dev/null +++ b/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrderTest.php @@ -0,0 +1,120 @@ + + */ + private array $filter; + + /** + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Exception + * @covers FilterWithBatchWithoutCountOrder::getTraversableList + * @testdox Get traversable list batch without count elements on every api call with elements count more than batch page size - 2500 elements + */ + public function testGetTraversableListBatchWithoutCountElementsOnEveryApiCallWithMoreThanBatchPageSizeFilterResult(): void + { + $this->assertTrue(true); + + $elementsCountByFilter = $this->serviceBuilder->getCRMScope()->deal()->countByFilter($this->filter); + $this->assertEquals(self::DEMO_DATA_ARRAY_SIZE_MORE_THAN_ONE_BATCH_PAGE_SIZE, $elementsCountByFilter); + + $select = [ + 'ID', + 'TITLE', + 'OPPORTUNITY', + ]; + + $elementsCount = 0; + $this->stopwatch->start('FilterWithBatchWithoutCountOrder.getTraversableList'); + foreach ($this->bulkItemsReader->getTraversableList('crm.deal.list', [], $this->filter, $select) as $cnt => $dealItem) { + $elementsCount++; + } + $this->stopwatch->stop('FilterWithBatchWithoutCountOrder.getTraversableList'); + $this->assertEquals( + $elementsCountByFilter, + $elementsCount, + sprintf( + 'elements count by filter %s not equals elements count from batch %s', + $elementsCountByFilter, + $elementsCount + ) + ); + + print(sprintf( + 'duration for FilterWithBatchWithoutCountOrder.getTraversableList: %s ms', + $this->stopwatch->getEvent('FilterWithBatchWithoutCountOrder.getTraversableList')->getDuration() + ) . PHP_EOL); + } + + public function setUp(): void + { + $this->stopwatch = new Stopwatch(true); + $this->serviceBuilder = Fabric::getServiceBuilder(); + $this->bulkItemsReader = new FilterWithBatchWithoutCountOrder( + Fabric::getBatchService(), + Fabric::getLogger() + ); + + // prepare demo data + // add contact + $this->contactId = $this->serviceBuilder->getCRMScope()->contact()->add( + [ + 'NAME' => sprintf('first_%s', time()), + 'SECOND' => sprintf('second_%s', time()), + ] + )->getId(); + + $this->filter = [ + 'CONTACT_ID' => $this->contactId, + ]; + + // add deals to bitrix24 + for ($i = 0; $i < self::DEMO_DATA_ARRAY_SIZE_MORE_THAN_ONE_BATCH_PAGE_SIZE; $i++) { + $rawDeals[] = [ + 'TITLE' => sprintf('deal-%s', $i), + 'IS_MANUAL_OPPORTUNITY' => 'Y', + 'OPPORTUNITY' => sprintf('%s.00', random_int(100, 40000)), + 'CURRENCY_ID' => 'RUB', + 'CONTACT_ID' => $this->contactId, + ]; + } + foreach ($this->serviceBuilder->getCRMScope()->deal()->batch->add($rawDeals) as $addDealResult) { + $this->dealId[] = $addDealResult->getId(); + } + } + + public function tearDown(): void + { + // clear demo data + $this->serviceBuilder->getCRMScope()->contact()->delete($this->contactId); + $cnt = 0; + foreach ($this->serviceBuilder->getCRMScope()->deal()->batch->delete($this->dealId) as $cnt => $result) { + $cnt++; + } + } +} \ No newline at end of file From 8aed9e258f129e7475086f4e6c3cff39b47eda2d Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 5 Feb 2022 22:50:57 +0300 Subject: [PATCH 279/647] fix integration tests for read strategies Signed-off-by: mesilov --- .../FilterWithBatchWithoutCountOrderTest.php | 3 - ...ilterWithoutBatchWithoutCountOrderTest.php | 138 +++++++----------- 2 files changed, 54 insertions(+), 87 deletions(-) diff --git a/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrderTest.php b/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrderTest.php index d64a599f..cc0ab621 100644 --- a/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrderTest.php +++ b/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrderTest.php @@ -22,7 +22,6 @@ class FilterWithBatchWithoutCountOrderTest extends TestCase */ private array $dealId; private const DEMO_DATA_ARRAY_SIZE_MORE_THAN_ONE_BATCH_PAGE_SIZE = 2555; - /** * @var array */ @@ -38,8 +37,6 @@ class FilterWithBatchWithoutCountOrderTest extends TestCase */ public function testGetTraversableListBatchWithoutCountElementsOnEveryApiCallWithMoreThanBatchPageSizeFilterResult(): void { - $this->assertTrue(true); - $elementsCountByFilter = $this->serviceBuilder->getCRMScope()->deal()->countByFilter($this->filter); $this->assertEquals(self::DEMO_DATA_ARRAY_SIZE_MORE_THAN_ONE_BATCH_PAGE_SIZE, $elementsCountByFilter); diff --git a/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrderTest.php b/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrderTest.php index 05e2913a..b9c5c374 100644 --- a/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrderTest.php +++ b/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrderTest.php @@ -10,61 +10,38 @@ use Bitrix24\SDK\Services\ServiceBuilder; use Bitrix24\SDK\Tests\Integration\Fabric; use PHPUnit\Framework\TestCase; -use Psr\Log\LoggerInterface; use Symfony\Component\Stopwatch\Stopwatch; class FilterWithoutBatchWithoutCountOrderTest extends TestCase { - protected Batch $batch; - protected ServiceBuilder $serviceBuilder; - protected LoggerInterface $log; - protected Stopwatch $stopwatch; - protected BulkItemsReaderInterface $bulkItemsReader; - private const DEMO_DATA_ARRAY_SIZE = 151; + private const DEMO_DATA_ARRAY_SIZE_MORE_THAN_ONE_BATCH_PAGE_SIZE = 2555; + private BulkItemsReaderInterface $bulkItemsReader; + private ServiceBuilder $serviceBuilder; + private Stopwatch $stopwatch; + private int $contactId; + /** + * @var int[] + */ + private array $dealId; + /** + * @var array + */ + private array $filter; + /** * @return void * @throws \Bitrix24\SDK\Core\Exceptions\BaseException * @throws \Bitrix24\SDK\Core\Exceptions\TransportException * @throws \Exception - * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface - * @covers \Bitrix24\SDK\Core\Batch::getTraversableListWithoutCount - * @testdox Добавление сущностей в batch режиме + * @covers \Bitrix24\SDK\Core\Batch::getTraversableList + * @testdox Get traversable list filter without batch without count ordered result */ - public function testGetTraversableListWithoutCountWithMoreThanPageSizeFilterResult(): void + public function testGetTraversableListFilterWithoutBatchWithoutCountOrder(): void { - // prepare demo data - $contactId = $this->serviceBuilder->getCRMScope()->contact()->add( - [ - 'NAME' => sprintf('first_%s', time()), - 'SECOND' => sprintf('second_%s', time()), - ] - )->getId(); + $elementsCountByFilter = $this->serviceBuilder->getCRMScope()->deal()->countByFilter($this->filter); + $this->assertEquals(self::DEMO_DATA_ARRAY_SIZE_MORE_THAN_ONE_BATCH_PAGE_SIZE, $elementsCountByFilter); - // add deals to bitrix24 - $rawDeals = []; - for ($i = 0; $i < self::DEMO_DATA_ARRAY_SIZE; $i++) { - $rawDeals[] = [ - 'TITLE' => sprintf('deal-%s', $i), - 'IS_MANUAL_OPPORTUNITY' => 'Y', - 'OPPORTUNITY' => sprintf('%s.00', random_int(100, 40000)), - 'CURRENCY_ID' => 'RUB', - 'CONTACT_ID' => $contactId, - ]; - } - $dealIdList = []; - foreach ($this->serviceBuilder->getCRMScope()->deal()->batch->add($rawDeals) as $addDealResult) { - $dealIdList[] = $addDealResult->getId(); - } - $this->assertCount(self::DEMO_DATA_ARRAY_SIZE, $dealIdList); - - // count added deals by default deal service - $filter = [ - 'CONTACT_ID' => $contactId, - ]; - - $elementsCountByFilter = $this->serviceBuilder->getCRMScope()->deal()->countByFilter($filter); - $this->assertEquals(self::DEMO_DATA_ARRAY_SIZE, $elementsCountByFilter); $select = [ 'ID', @@ -72,50 +49,17 @@ public function testGetTraversableListWithoutCountWithMoreThanPageSizeFilterResu 'OPPORTUNITY', ]; - $elementsCount = 0; - $this->stopwatch->start('batch.list.with.count'); - foreach ($this->batch->getTraversableList('crm.deal.list', [], $filter, $select) as $cnt => $dealItem) { - $elementsCount++; -// print(sprintf( -// '%s-%s| %s | %s - %s', -// $cnt, -// $elementsCountByFilter, -// $dealItem['ID'], -// $dealItem['TITLE'], -// $dealItem['OPPORTUNITY'], -// ) . PHP_EOL); - } - $this->stopwatch->stop('batch.list.with.count'); - $this->assertEquals( - $elementsCountByFilter, - $elementsCount, - sprintf( - 'elements count by filter %s not equals elements count from batch %s', - $elementsCountByFilter, - $elementsCount - ) - ); - - $elementsCount = 0; $this->stopwatch->start('FilterWithoutBatchWithoutCountOrder'); foreach ( $this->bulkItemsReader->getTraversableList( 'crm.deal.list', ['ID' => 'ASC'], - $filter, + $this->filter, $select ) as $cnt => $dealItem ) { $elementsCount++; -// print(sprintf( -// '%s-%s| %s | %s - %s', -// $cnt, -// $elementsCountByFilter, -// $dealItem['ID'], -// $dealItem['TITLE'], -// $dealItem['OPPORTUNITY'], -// ) . PHP_EOL); } $this->stopwatch->stop('FilterWithoutBatchWithoutCountOrder'); $this->assertEquals( @@ -128,11 +72,6 @@ public function testGetTraversableListWithoutCountWithMoreThanPageSizeFilterResu ) ); - print('=====' . PHP_EOL); - print(sprintf( - 'duration for batch list with count: %s ms', - $this->stopwatch->getEvent('batch.list.with.count')->getDuration() - ) . PHP_EOL); print(sprintf( 'FilterWithoutBatchWithoutCountOrder: %s ms', $this->stopwatch->getEvent('FilterWithoutBatchWithoutCountOrder')->getDuration() @@ -144,16 +83,47 @@ public function testGetTraversableListWithoutCountWithMoreThanPageSizeFilterResu public function setUp(): void { $this->stopwatch = new Stopwatch(true); - $this->batch = Fabric::getBatchService(); $this->serviceBuilder = Fabric::getServiceBuilder(); - $this->log = Fabric::getLogger(); $this->bulkItemsReader = new FilterWithoutBatchWithoutCountOrder( Fabric::getCore(), - $this->log + Fabric::getLogger() ); + + // prepare demo data + // add contact + $this->contactId = $this->serviceBuilder->getCRMScope()->contact()->add( + [ + 'NAME' => sprintf('first_%s', time()), + 'SECOND' => sprintf('second_%s', time()), + ] + )->getId(); + + $this->filter = [ + 'CONTACT_ID' => $this->contactId, + ]; + + // add deals to bitrix24 + for ($i = 0; $i < self::DEMO_DATA_ARRAY_SIZE_MORE_THAN_ONE_BATCH_PAGE_SIZE; $i++) { + $rawDeals[] = [ + 'TITLE' => sprintf('deal-%s', $i), + 'IS_MANUAL_OPPORTUNITY' => 'Y', + 'OPPORTUNITY' => sprintf('%s.00', random_int(100, 40000)), + 'CURRENCY_ID' => 'RUB', + 'CONTACT_ID' => $this->contactId, + ]; + } + foreach ($this->serviceBuilder->getCRMScope()->deal()->batch->add($rawDeals) as $addDealResult) { + $this->dealId[] = $addDealResult->getId(); + } } public function tearDown(): void { + // clear demo data + $this->serviceBuilder->getCRMScope()->contact()->delete($this->contactId); + $cnt = 0; + foreach ($this->serviceBuilder->getCRMScope()->deal()->batch->delete($this->dealId) as $cnt => $result) { + $cnt++; + } } } \ No newline at end of file From bb6be7aad11502ccf26bacce0c0de02d0a8ab7c3 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 5 Feb 2022 23:09:33 +0300 Subject: [PATCH 280/647] fix demo generator for contact Signed-off-by: mesilov --- .../CRM/Contacts/GenerateContactsCommand.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tools/DemoDataGenerators/CRM/Contacts/GenerateContactsCommand.php b/tools/DemoDataGenerators/CRM/Contacts/GenerateContactsCommand.php index 5da48d7c..1a37e3a9 100644 --- a/tools/DemoDataGenerators/CRM/Contacts/GenerateContactsCommand.php +++ b/tools/DemoDataGenerators/CRM/Contacts/GenerateContactsCommand.php @@ -5,6 +5,7 @@ namespace Bitrix24\SDK\Tools\DemoDataGenerators\CRM\Contacts; use Bitrix24\SDK\Core\Batch; +use Bitrix24\SDK\Core\BulkItemsReader\BulkItemsReaderBuilder; use Bitrix24\SDK\Core\CoreBuilder; use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Services\ServiceBuilder; @@ -110,13 +111,24 @@ protected function execute(InputInterface $input, OutputInterface $output): int ); try { + // todo create service builder factory $core = (new CoreBuilder()) ->withLogger($this->logger) ->withWebhookUrl($b24Webhook) ->build(); + $batch = new Batch( + $core, + $this->logger + ); $services = new ServiceBuilder( $core, - new Batch($core, $this->logger), + $batch, + (new BulkItemsReaderBuilder( + $core, + $batch, + $this->logger + )) + ->build(), $this->logger ); From bb617f7fc90b96532a9ee0abaf84c0208fb5a6eb Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 5 Feb 2022 23:44:36 +0300 Subject: [PATCH 281/647] update performance benchmark Signed-off-by: mesilov --- tools/.env | 2 +- tools/PerformanceBenchmarks/ListCommand.php | 98 +++++++++++++++++---- 2 files changed, 84 insertions(+), 16 deletions(-) diff --git a/tools/.env b/tools/.env index 1581fc9b..7ad07ba6 100644 --- a/tools/.env +++ b/tools/.env @@ -1,3 +1,3 @@ APP_ENV=dev LOGS_FILE=tools/logs/cli.log -LOGS_LEVEL=100 \ No newline at end of file +LOGS_LEVEL=200 \ No newline at end of file diff --git a/tools/PerformanceBenchmarks/ListCommand.php b/tools/PerformanceBenchmarks/ListCommand.php index c7548d2c..309d98fc 100644 --- a/tools/PerformanceBenchmarks/ListCommand.php +++ b/tools/PerformanceBenchmarks/ListCommand.php @@ -4,7 +4,10 @@ namespace Bitrix24\SDK\Tools\PerformanceBenchmarks; -use Bitrix24\SDK\Core\Core; +use Bitrix24\SDK\Core\Batch; +use Bitrix24\SDK\Core\Contracts\BatchInterface; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\CoreBuilder; use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Exceptions\TransportException; use Psr\Log\LoggerInterface; @@ -28,7 +31,8 @@ class ListCommand extends Command { protected LoggerInterface $logger; - protected Core $core; + protected CoreInterface $core; + protected BatchInterface $batch; /** * @var string */ @@ -141,10 +145,14 @@ protected function execute(InputInterface $input, OutputInterface $output): int ] ); - $this->core = (new \Bitrix24\SDK\Core\CoreBuilder()) + $this->core = (new CoreBuilder()) ->withLogger($this->logger) ->withWebhookUrl($b24Webhook) ->build(); + $this->batch = new Batch( + $this->core, + $this->logger + ); $countResult = $this->core->call('crm.contact.list'); $output->writeln(['======', '']); @@ -168,9 +176,14 @@ protected function execute(InputInterface $input, OutputInterface $output): int $table = new Table($output); $table->setHeaders(['Mode', 'Time']); $table->addRow([$this->benchmarkItems['order_count'], round($result['order_count'], self::TIME_PRECISION)]); - $table->addRow([$this->benchmarkItems['order_without_count'], 'not implemented']); + $table->addRow([$this->benchmarkItems['order_without_count'], round($result['order_without_count'], self::TIME_PRECISION)]); $table->addRow([$this->benchmarkItems['without_order_count'], round($result['without_order_count'], self::TIME_PRECISION)]); - $table->addRow([$this->benchmarkItems['without_order_without_count'], 'not implemented']); + $table->addRow( + [ + $this->benchmarkItems['without_order_without_count'], + round($result['without_order_without_count'], self::TIME_PRECISION), + ] + ); $table->render(); } else { $output->writeln('crm.contact.list - get first 50 elements...'); @@ -244,16 +257,16 @@ protected function batchList(OutputInterface $output, array $order, array $filte $result = []; $output->writeln(['', '1. batch requests - ordered, count total elements...', '']); - $result['order_count'] = $this->getBatchQueryTime($output, $order, $filter, $select, $elementsCount); + $result['order_count'] = $this->getBatchWithCountQueryTime($output, $order, $filter, $select, $elementsCount); - $output->writeln(['', '2. batch requests - ordered, without count total elements | NOT IMPLEMENTED', '']); - $result['order_without_count'] = null; + $output->writeln(['', '2. batch requests - ordered, without count total elements...', '']); + $result['order_without_count'] = $this->getBatchWithoutCountQueryTime($output, $order, $filter, $select, $elementsCount); $output->writeln(['', '3. batch requests - default order, count total elements...', '']); - $result['without_order_count'] = $this->getBatchQueryTime($output, [], $filter, $select, $elementsCount); + $result['without_order_count'] = $this->getBatchWithCountQueryTime($output, [], $filter, $select, $elementsCount); - $output->writeln(['', '4. batch requests - default order, without count total elements | NOT IMPLEMENTED', '']); - $result['without_order_without_count'] = null; + $output->writeln(['', '4. batch requests - default order, without count total elements...', '']); + $result['without_order_without_count'] = $this->getBatchWithoutCountQueryTime($output, [], $filter, $select, $elementsCount);; return $result; } @@ -273,17 +286,72 @@ protected function batchList(OutputInterface $output, array $order, array $filte * @throws TransportException * @throws TransportExceptionInterface */ - protected function getBatchQueryTime(OutputInterface $output, array $order, array $filter, array $select, int $elementsCount): float - { + protected function getBatchWithCountQueryTime( + OutputInterface $output, + array $order, + array $filter, + array $select, + int $elementsCount + ): float { + $timeStart = microtime(true); + $progressBar = new ProgressBar($output, $elementsCount); + $progressBar->setFormat("%current%/%max% [%bar%] %percent:3s%%\n %memory:6s% | %status%\n"); + $progressBar->setMessage('wait first batch query result...', 'status'); + $progressBar->start(); + + $elementsFromBatchCount = 0; + foreach ($this->batch->getTraversableListWithCount('crm.contact.list', $order, $filter, $select, $elementsCount) as $queryItem) { + $curTime = microtime(true); + $elementsFromBatchCount++; + $progressBar->advance(); + + $progressBar->setMessage( + sprintf( + ' %s sec |# %s | %s - %s ', + round($curTime - $timeStart, 2), + $elementsFromBatchCount, + $queryItem['ID'], + $queryItem['NAME'] + ), + 'status' + ); + } + $timeEnd = microtime(true); + $progressBar->finish(); + + return $timeEnd - $timeStart; + } + + /** + * @param OutputInterface $output + * @param array $order + * @param array $filter + * @param array $select + * @param int $elementsCount + * + * @return float + * @throws BaseException + * @throws ClientExceptionInterface + * @throws RedirectionExceptionInterface + * @throws ServerExceptionInterface + * @throws TransportException + * @throws TransportExceptionInterface + */ + protected function getBatchWithoutCountQueryTime( + OutputInterface $output, + array $order, + array $filter, + array $select, + int $elementsCount + ): float { $timeStart = microtime(true); - $batch = new \Bitrix24\SDK\Core\Batch($this->core, $this->logger); $progressBar = new ProgressBar($output, $elementsCount); $progressBar->setFormat("%current%/%max% [%bar%] %percent:3s%%\n %memory:6s% | %status%\n"); $progressBar->setMessage('wait first batch query result...', 'status'); $progressBar->start(); $elementsFromBatchCount = 0; - foreach ($batch->getTraversableList('crm.contact.list', $order, $filter, $select, $elementsCount) as $queryItem) { + foreach ($this->batch->getTraversableList('crm.contact.list', $order, $filter, $select, $elementsCount) as $queryItem) { $curTime = microtime(true); $elementsFromBatchCount++; $progressBar->advance(); From 72a880dc14a3c80eac0ea81f8421795805e3f984 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 00:28:15 +0300 Subject: [PATCH 282/647] fix integration tests Signed-off-by: mesilov --- tests/Integration/Core/BatchTest.php | 19 +++++-------------- .../FilterWithBatchWithoutCountOrderTest.php | 2 +- ...ilterWithoutBatchWithoutCountOrderTest.php | 2 +- 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/tests/Integration/Core/BatchTest.php b/tests/Integration/Core/BatchTest.php index b77a9446..6221f217 100644 --- a/tests/Integration/Core/BatchTest.php +++ b/tests/Integration/Core/BatchTest.php @@ -18,7 +18,6 @@ class BatchTest extends TestCase private Stopwatch $stopwatch; private const DEMO_DATA_ARRAY_SIZE_LESS_THAN_PAGE = 35; private const DEMO_DATA_ARRAY_SIZE_MORE_THAN_ONE_PAGE_SIZE = 65; - private const DEMO_DATA_ARRAY_SIZE_MORE_THAN_MAX_BATCH_PAGE_COUNT = 2735; private const LIMIT_ELEMENTS_IN_RESULT = 10; /** @@ -42,7 +41,7 @@ public function testGetTraversableListWithMoreThanMaxBatchPageCountWithoutLimit( // add deals to bitrix24 $rawDeals = []; - for ($i = 0; $i < self::DEMO_DATA_ARRAY_SIZE_MORE_THAN_MAX_BATCH_PAGE_COUNT; $i++) { + for ($i = 0; $i < self::DEMO_DATA_ARRAY_SIZE_MORE_THAN_ONE_PAGE_SIZE; $i++) { $rawDeals[] = [ 'TITLE' => sprintf('deal-%s', $i), 'IS_MANUAL_OPPORTUNITY' => 'Y', @@ -55,7 +54,7 @@ public function testGetTraversableListWithMoreThanMaxBatchPageCountWithoutLimit( foreach ($this->serviceBuilder->getCRMScope()->deal()->batch->add($rawDeals) as $addDealResult) { $dealIdList[] = $addDealResult->getId(); } - $this->assertCount(self::DEMO_DATA_ARRAY_SIZE_MORE_THAN_MAX_BATCH_PAGE_COUNT, $dealIdList); + $this->assertCount(self::DEMO_DATA_ARRAY_SIZE_MORE_THAN_ONE_PAGE_SIZE, $dealIdList); // count added deals by default deal service @@ -64,7 +63,7 @@ public function testGetTraversableListWithMoreThanMaxBatchPageCountWithoutLimit( ]; $elementsCountByFilter = $this->serviceBuilder->getCRMScope()->deal()->countByFilter($filter); - $this->assertEquals(self::DEMO_DATA_ARRAY_SIZE_MORE_THAN_MAX_BATCH_PAGE_COUNT, $elementsCountByFilter); + $this->assertEquals(self::DEMO_DATA_ARRAY_SIZE_MORE_THAN_ONE_PAGE_SIZE, $elementsCountByFilter); $select = [ '*', @@ -76,18 +75,10 @@ public function testGetTraversableListWithMoreThanMaxBatchPageCountWithoutLimit( foreach ($this->batch->getTraversableList('crm.deal.list', [], $filter, $select) as $cnt => $dealItem) { $batchElementsCount++; $dealIdListFromBatch[] = $dealItem['ID']; - print(sprintf( - '%s-%s| %s | %s - %s', - $cnt, - self::DEMO_DATA_ARRAY_SIZE_MORE_THAN_MAX_BATCH_PAGE_COUNT, - $dealItem['ID'], - $dealItem['TITLE'], - $dealItem['OPPORTUNITY'], - ) . PHP_EOL); } $this->stopwatch->stop('getTraversableList'); $this->assertEquals( - self::DEMO_DATA_ARRAY_SIZE_MORE_THAN_MAX_BATCH_PAGE_COUNT, + self::DEMO_DATA_ARRAY_SIZE_MORE_THAN_ONE_PAGE_SIZE, $batchElementsCount, sprintf( 'elements count by filter %s not equals elements count from batch getTraversableList %s', @@ -109,7 +100,7 @@ public function testGetTraversableListWithMoreThanMaxBatchPageCountWithoutLimit( $deletedItemsCount++; } $this->assertEquals( - self::DEMO_DATA_ARRAY_SIZE_MORE_THAN_MAX_BATCH_PAGE_COUNT, + self::DEMO_DATA_ARRAY_SIZE_MORE_THAN_ONE_PAGE_SIZE, $deletedItemsCount, sprintf( 'elements count by filter %s not equals deleted elements count from batch deleteEntityItems %s', diff --git a/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrderTest.php b/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrderTest.php index cc0ab621..3c37725d 100644 --- a/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrderTest.php +++ b/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrderTest.php @@ -21,7 +21,7 @@ class FilterWithBatchWithoutCountOrderTest extends TestCase * @var int[] */ private array $dealId; - private const DEMO_DATA_ARRAY_SIZE_MORE_THAN_ONE_BATCH_PAGE_SIZE = 2555; + private const DEMO_DATA_ARRAY_SIZE_MORE_THAN_ONE_BATCH_PAGE_SIZE = 65; /** * @var array */ diff --git a/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrderTest.php b/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrderTest.php index b9c5c374..9d6b7002 100644 --- a/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrderTest.php +++ b/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrderTest.php @@ -14,7 +14,7 @@ class FilterWithoutBatchWithoutCountOrderTest extends TestCase { - private const DEMO_DATA_ARRAY_SIZE_MORE_THAN_ONE_BATCH_PAGE_SIZE = 2555; + private const DEMO_DATA_ARRAY_SIZE_MORE_THAN_ONE_BATCH_PAGE_SIZE = 65; private BulkItemsReaderInterface $bulkItemsReader; private ServiceBuilder $serviceBuilder; private Stopwatch $stopwatch; From 3cda0f85041e79b805c128c944e578cd8fa0efd0 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 01:19:12 +0300 Subject: [PATCH 283/647] add integration-tests workflow Signed-off-by: mesilov --- .github/workflows/integration-tests.yml | 44 +++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 .github/workflows/integration-tests.yml diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml new file mode 100644 index 00000000..d84981ea --- /dev/null +++ b/.github/workflows/integration-tests.yml @@ -0,0 +1,44 @@ +name: "Integration tests" + +on: + push: + branches: + - 'master' + - 'dev' + - '2.x' + - '248-fast-batch' + paths: + - 'src/**' + - 'tests/**' + +env: + COMPOSER_FLAGS: "--ansi --no-interaction --no-progress --prefer-dist" + +jobs: + tests: + name: "Integration tests" + + runs-on: ubuntu-latest + + strategy: + matrix: + php-version: + - "7.4" + dependencies: [ highest ] + + steps: + - name: "Checkout" + uses: "actions/checkout@v2" + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + coverage: "none" + php-version: "${{ matrix.php-version }}" + + - name: "Install dependencies" + run: | + composer update ${{ env.COMPOSER_FLAGS }} + + - name: "run unit tests" + run: "composer phpunit-run-integration-tests" \ No newline at end of file From 80f62344e5f9db8cb85d1c6a1744d32cde8511c8 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 01:32:16 +0300 Subject: [PATCH 284/647] add integration-tests workflow2 Signed-off-by: mesilov --- .github/workflows/integration-tests.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index d84981ea..68c6a9c6 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -6,7 +6,6 @@ on: - 'master' - 'dev' - '2.x' - - '248-fast-batch' paths: - 'src/**' - 'tests/**' From 93ac5357c4f99390da3772311bb2393760ed7668 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 01:48:11 +0300 Subject: [PATCH 285/647] add integration-tests workflow settings Signed-off-by: mesilov --- tests/.env | 2 +- tests/Integration/Fabric.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/.env b/tests/.env index fb14da23..481d15ae 100644 --- a/tests/.env +++ b/tests/.env @@ -18,4 +18,4 @@ APP_ENV=dev BITRIX24_WEBHOOK= # monolog log level -INTEGRATION_TEST_LOG_LEVEL= \ No newline at end of file +INTEGRATION_TEST_LOG_LEVEL=200 \ No newline at end of file diff --git a/tests/Integration/Fabric.php b/tests/Integration/Fabric.php index ada1d33f..42bd1c8e 100644 --- a/tests/Integration/Fabric.php +++ b/tests/Integration/Fabric.php @@ -47,7 +47,7 @@ public static function getCore(): CoreInterface { return (new CoreBuilder()) ->withLogger(self::getLogger()) - ->withWebhookUrl($_ENV['BITRIX24_WEBHOOK']) + ->withWebhookUrl($_ENV['BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK'] ?? $_ENV['BITRIX24_WEBHOOK']) ->build(); } From bb75c1701575b01f355e1b435d3467760e784be0 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 01:59:27 +0300 Subject: [PATCH 286/647] set secrets for integration-tests Signed-off-by: mesilov --- .github/workflows/integration-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 68c6a9c6..ac3e3da8 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -12,7 +12,7 @@ on: 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" From 87b9f184b695ee05eebfeee34020b7e303d696f5 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 02:11:02 +0300 Subject: [PATCH 287/647] =?UTF-8?q?=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=D0=B8=20=D0=B4=D0=BE=D0=BA=D1=83=D0=BC=D0=B5=D0=BD=D1=82?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: mesilov --- docs/RU/Core/Batch/batch-read-mode.md | 31 +++++++++++++-------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/docs/RU/Core/Batch/batch-read-mode.md b/docs/RU/Core/Batch/batch-read-mode.md index dc81e663..11d4634c 100644 --- a/docs/RU/Core/Batch/batch-read-mode.md +++ b/docs/RU/Core/Batch/batch-read-mode.md @@ -88,22 +88,21 @@ Help: Режим | отдельные поля | вся сущность | вся сущность + UF_* --- | --- | --- | --- -сортировка, подсчёт количества элементов в выборке | 0.1724 | 1.9875 | 2.3136 -сортировка, без подсчёта количества элементов в выборке | 0.1173 | 1.3289 | 1.476 -сортировка по умолчанию, подсчёт количества элементов в выборке | 0.0936 | 0.926 | 1.0272 -сортировка по умолчанию, без подсчёта количества элементов в выборке | 0.0362 | 0.2701 | 0.2688 +сортировка, подсчёт количества элементов в выборке | 0.3786 | 2.6767 | 3.1891 +сортировка, без подсчёта количества элементов в выборке | 0.3125 | 1.745 | 1.956 +сортировка по умолчанию, подсчёт количества элементов в выборке | 0.3129 | 1.3176 | 1.523 +сортировка по умолчанию, без подсчёта количества элементов в выборке | **0.2241** | **0.458** | **0.4858** -### Чтение 6000 элементов — отдельные поля \ вся сущность \ вся сущность + пользовательские поля +### Чтение 2700 элементов в batch-режиме отдельные поля \ вся сущность \ вся сущность + пользовательские поля -В данном примере используются batch-запросы, которые выбирают данные чанками по 2500, 2500 и 1000 элементов. Сами батч запросы реализуются -сервисом `Bitrix24\SDK\Core\Batch` Время — секунды, округление до 4 знаков. +Сами запросы строятся сервисом `Bitrix24\SDK\Core\Batch` Время — секунды, округление до 4 знаков. Режим | отдельные поля | вся сущность | вся сущность + UF_* --- | --- | --- | --- -сортировка, подсчёт количества элементов в выборке | 17.8018 | 239.8081 | 274.9921 -сортировка, без подсчёта количества элементов в выборке | **not implemented** | **not implemented** | **not implemented** -сортировка по умолчанию, подсчёт количества элементов в выборке | 8.2121 | 110.0122 | 125.7331 -сортировка по умолчанию, без подсчёта количества элементов в выборке | **not implemented** | **not implemented** | **not implemented** +сортировка, подсчёт количества элементов в выборке | 19.7924 | 131.3065 | 168.753 +сортировка, без подсчёта количества элементов в выборке | 27.0083 | **30.8689** | **32.6827** +сортировка по умолчанию, подсчёт количества элементов в выборке | **14.3636** | 70.5149 | 79.5987 +сортировка по умолчанию, без подсчёта количества элементов в выборке | 26.5045 | 31.1381 | 33.8329 ## Подготовка тестового окружения @@ -115,8 +114,8 @@ Help: 1. В текущей версии статьи в портале было 100к элементов в сущности, эта ситуация характерна для небольшого количества порталов 2. Замеры производились когда на портале отсутствовала операционная нагрузка характерная для рабочего дня 3. По возможности старайтесь избегать выборки всех данных -4. Сортировка данных при больших выборках тоже слишком дорогая операция -5. В roadmap SDK будет добавлена задача на поддержку batch-запросов в режиме «отключенный подсчёт количества» элементов, сейчас там - указано **not implemented** -6. Замеры будут проведены для кейсов от 10к до 200к элементов с шагом 10к элементов. -7. В коробочной версии Битрикс24 показатели могут существенно отличаться +4. Сортировка данных при больших выборках тоже дорогая операция +5. Имеет смысл сделать замеры при изменении количества элементов на портале 10к до 500к элементов с шагом 20к элементов. +6. В коробочной версии Битрикс24 показатели могут существенно отличаться +7. В SDK выделен отдельный сервис `Core\BulkItemsReader` который реализует более эффективные стратегии чем простой batch, на текущий момент + оптимизация скорости чтения данных не производилась, используется стратегия «батч без подсчёта количества элементов» From e123b3403e2b304ba9af3d3aa7b4b406aa67b8f8 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 02:22:48 +0300 Subject: [PATCH 288/647] test ci\cd Signed-off-by: mesilov --- tests/Integration/Fabric.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/Integration/Fabric.php b/tests/Integration/Fabric.php index 42bd1c8e..dcf0e876 100644 --- a/tests/Integration/Fabric.php +++ b/tests/Integration/Fabric.php @@ -12,6 +12,8 @@ use Bitrix24\SDK\Services\ServiceBuilder; use Monolog\Handler\StreamHandler; use Monolog\Logger; +use Monolog\Processor\IntrospectionProcessor; +use Monolog\Processor\MemoryUsageProcessor; use Psr\Log\LoggerInterface; /** @@ -58,8 +60,8 @@ public static function getLogger(): LoggerInterface { $log = new Logger('integration-test'); $log->pushHandler(new StreamHandler(STDOUT, (int)$_ENV['INTEGRATION_TEST_LOG_LEVEL'])); - $log->pushProcessor(new \Monolog\Processor\MemoryUsageProcessor(true, true)); - $log->pushProcessor(new \Monolog\Processor\IntrospectionProcessor()); + $log->pushProcessor(new MemoryUsageProcessor(true, true)); + $log->pushProcessor(new IntrospectionProcessor()); return $log; } From 4c22992bf3461c539d912499629e749a501de206 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 02:24:53 +0300 Subject: [PATCH 289/647] test ci\cd 2 Signed-off-by: mesilov --- .github/workflows/integration-tests.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index ac3e3da8..0af6c0cf 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -3,12 +3,7 @@ name: "Integration tests" on: push: branches: - - 'master' - 'dev' - - '2.x' - paths: - - 'src/**' - - 'tests/**' env: COMPOSER_FLAGS: "--ansi --no-interaction --no-progress --prefer-dist" From 3c3f4e503afa0e4809a5e367a976da28d6aeb924 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 02:27:35 +0300 Subject: [PATCH 290/647] test ci\cd 3 Signed-off-by: mesilov --- .github/workflows/integration-tests.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 0af6c0cf..be74c09d 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -1,9 +1,8 @@ -name: "Integration tests" - on: push: - branches: - - 'dev' + pull_request: + +name: "Integration tests" env: COMPOSER_FLAGS: "--ansi --no-interaction --no-progress --prefer-dist" From 380d457dd1156de547621c5de7ed5ce11aabb25b Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 02:30:07 +0300 Subject: [PATCH 291/647] test ci\cd 4 Signed-off-by: mesilov --- .../workflows/{integration-tests.yml => integration.yml} | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) rename .github/workflows/{integration-tests.yml => integration.yml} (96%) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration.yml similarity index 96% rename from .github/workflows/integration-tests.yml rename to .github/workflows/integration.yml index be74c09d..0b2c56b1 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration.yml @@ -1,9 +1,9 @@ -on: - push: - pull_request: - name: "Integration tests" +on: + - push + - pull_request + env: COMPOSER_FLAGS: "--ansi --no-interaction --no-progress --prefer-dist" BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK: ${{ secrets.BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK }} From 42ce06e9dcd8cbce47d8842e9448d1dfa572db1f Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 02:32:14 +0300 Subject: [PATCH 292/647] test ci\cd 5 Signed-off-by: mesilov --- .../ReadStrategies/FilterWithoutBatchWithoutCountOrder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrder.php b/src/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrder.php index bc49bc7d..a2d1ce9e 100644 --- a/src/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrder.php +++ b/src/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrder.php @@ -45,7 +45,7 @@ public function getTraversableList(string $apiMethod, array $order, array $filte 'limit' => $limit, ]); - // дефолтная стратегия из документации https://dev.1c-bitrix.ru/rest_help/rest_sum/start.php + // Дефолтная стратегия из документации https://dev.1c-bitrix.ru/rest_help/rest_sum/start.php // //Особенности: //— ✅ отключён подсчёт количества элементов в выборке From 593105ff88e6c3eb27e237691b19ef795ee4eab1 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 02:45:40 +0300 Subject: [PATCH 293/647] test ci\cd 6 Signed-off-by: mesilov --- .github/workflows/integration.yml | 4 ++-- src/Core/Batch.php | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 0b2c56b1..ca338a6c 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -1,8 +1,8 @@ name: "Integration tests" on: - - push - - pull_request + push: + pull_request: env: COMPOSER_FLAGS: "--ansi --no-interaction --no-progress --prefer-dist" diff --git a/src/Core/Batch.php b/src/Core/Batch.php index 9f8e640d..03379d3a 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -608,6 +608,7 @@ protected function getTraversable(bool $isHaltOnError): Generator 'batchApiCommandUuid' => $batchResult->getApiCommand()->getUuid()->toString(), ] ); + // todo try to multiplex requests $response = $batchResult->getResponseData(); // single queries From 937f6f177baa7867b30fce5552c3b279709a8d6d Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 02:55:27 +0300 Subject: [PATCH 294/647] test ci\cd 7 Signed-off-by: mesilov --- tests/Integration/Fabric.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/Integration/Fabric.php b/tests/Integration/Fabric.php index dcf0e876..dd002138 100644 --- a/tests/Integration/Fabric.php +++ b/tests/Integration/Fabric.php @@ -47,6 +47,10 @@ public static function getBulkItemsReader(): BulkItemsReaderInterface */ public static function getCore(): CoreInterface { + print(print_r($_ENV, true)); + print(print_r($_ENV['BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK'])); + print(print_r($_ENV['BITRIX24_WEBHOOK'])); + return (new CoreBuilder()) ->withLogger(self::getLogger()) ->withWebhookUrl($_ENV['BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK'] ?? $_ENV['BITRIX24_WEBHOOK']) From 1eb01652872571fabe11c9aaec2856f9b3bcfed7 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 02:58:17 +0300 Subject: [PATCH 295/647] test ci\cd 8 Signed-off-by: mesilov --- tests/Integration/Fabric.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Integration/Fabric.php b/tests/Integration/Fabric.php index dd002138..ffc5e946 100644 --- a/tests/Integration/Fabric.php +++ b/tests/Integration/Fabric.php @@ -50,6 +50,7 @@ public static function getCore(): CoreInterface print(print_r($_ENV, true)); print(print_r($_ENV['BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK'])); print(print_r($_ENV['BITRIX24_WEBHOOK'])); + exit(); return (new CoreBuilder()) ->withLogger(self::getLogger()) From b5bdadcd12ed5a454266e42444f4f134e1956ae5 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 03:02:57 +0300 Subject: [PATCH 296/647] test ci\cd 9 Signed-off-by: mesilov --- tests/Integration/Fabric.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Integration/Fabric.php b/tests/Integration/Fabric.php index ffc5e946..4c66602d 100644 --- a/tests/Integration/Fabric.php +++ b/tests/Integration/Fabric.php @@ -47,6 +47,7 @@ public static function getBulkItemsReader(): BulkItemsReaderInterface */ public static function getCore(): CoreInterface { + print(print_r($_ENV, true)); print(print_r($_ENV['BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK'])); print(print_r($_ENV['BITRIX24_WEBHOOK'])); From e8fc6b82155ef65ee66def6155858b6004da58a4 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 09:41:12 +0300 Subject: [PATCH 297/647] test ci\cd 10 Signed-off-by: mesilov --- .github/workflows/integration.yml | 24 ++++++++++++++++++++++++ tests/bootstrap.php | 4 +++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index ca338a6c..db3c99ba 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -20,6 +20,29 @@ jobs: dependencies: [ highest ] steps: + - name: "debug env" + run: | + echo " " + echo "$(cat TAG_EDGE_VERSION_HASH) < TAG_EDGE_VERSION_HASH" + echo "$(cat TAG_EDGE_VERSION) < TAG_EDGE_VERSION" + echo "$(cat TAG_EDGE) < TAG_EDGE" + echo " " + echo "$(cat TAG_EDGE_VERSION_HASH_GPR) < TAG_EDGE_VERSION_HASH_GPR" + echo "$(cat TAG_EDGE_VERSION_GPR) < TAG_EDGE_VERSION_GPR" + echo "$(cat TAG_EDGE_GPR) < TAG_EDGE_GPR" + echo " " + echo "$(cat APP_NAME) < APP_NAME" + echo "$(cat VERSION) < VERSION" + echo "$(cat DOCKERFILE_NAME) < DOCKERFILE_NAME" + echo " " + echo "$(cat DATE_TIME) < DATE_TIME" + echo "$(cat SHORT_COMMIT_HASH) < SHORT_COMMIT_HASH" + echo "$(cat DOCKERHUB_USER) < DOCKERHUB_USER" + echo "$(cat GITHUB_ORG) < GITHUB_ORG" + echo "$(cat DKR_HUB_URL) < DKR_HUB_URL" + echo "$(cat GPR_URL) < GPR_URL" + echo "$(cat GITHUB_REGISTRY) < GITHUB_REGISTRY" + - name: "Checkout" uses: "actions/checkout@v2" @@ -31,6 +54,7 @@ jobs: - name: "Install dependencies" run: | + printenv BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK composer update ${{ env.COMPOSER_FLAGS }} - name: "run unit tests" diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 0e854a6b..11b8d641 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -20,4 +20,6 @@ putenv('APP_DEBUG=' . $_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = '0'); } -(new Dotenv())->loadEnv(dirname(__DIR__).'/tests/.env'); \ No newline at end of file +(new Dotenv())->loadEnv(dirname(__DIR__) . '/tests/.env'); + +phpinfo(); \ No newline at end of file From 825c6ce836f4abb7f508f09acaa8a0c74d928046 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 09:43:52 +0300 Subject: [PATCH 298/647] test ci\cd 11 Signed-off-by: mesilov --- .github/workflows/integration.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index db3c99ba..afc023e5 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -2,6 +2,8 @@ name: "Integration tests" on: push: + branches: + - dev pull_request: env: From 5548b5b7bc1363949fd19b6281577c88bd665bdf Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 09:45:40 +0300 Subject: [PATCH 299/647] test ci\cd 12 Signed-off-by: mesilov --- .github/workflows/integration.yml | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index afc023e5..77e7f193 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -23,27 +23,10 @@ jobs: steps: - name: "debug env" - run: | - echo " " - echo "$(cat TAG_EDGE_VERSION_HASH) < TAG_EDGE_VERSION_HASH" - echo "$(cat TAG_EDGE_VERSION) < TAG_EDGE_VERSION" - echo "$(cat TAG_EDGE) < TAG_EDGE" - echo " " - echo "$(cat TAG_EDGE_VERSION_HASH_GPR) < TAG_EDGE_VERSION_HASH_GPR" - echo "$(cat TAG_EDGE_VERSION_GPR) < TAG_EDGE_VERSION_GPR" - echo "$(cat TAG_EDGE_GPR) < TAG_EDGE_GPR" - echo " " - echo "$(cat APP_NAME) < APP_NAME" - echo "$(cat VERSION) < VERSION" - echo "$(cat DOCKERFILE_NAME) < DOCKERFILE_NAME" - echo " " - echo "$(cat DATE_TIME) < DATE_TIME" - echo "$(cat SHORT_COMMIT_HASH) < SHORT_COMMIT_HASH" - echo "$(cat DOCKERHUB_USER) < DOCKERHUB_USER" - echo "$(cat GITHUB_ORG) < GITHUB_ORG" - echo "$(cat DKR_HUB_URL) < DKR_HUB_URL" - echo "$(cat GPR_URL) < GPR_URL" - echo "$(cat GITHUB_REGISTRY) < GITHUB_REGISTRY" + run: | + echo " " + printenv BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK + printenv - name: "Checkout" uses: "actions/checkout@v2" From 974b18fba82e7469828753f78c9f76cf8d7cd3fe Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 09:53:29 +0300 Subject: [PATCH 300/647] test ci\cd 13 Signed-off-by: mesilov --- .github/workflows/integration.yml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 77e7f193..44def89b 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -8,7 +8,7 @@ on: 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" @@ -36,11 +36,15 @@ jobs: with: coverage: "none" php-version: "${{ matrix.php-version }}" + env: + BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK: ${{ secrets.BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK }} - name: "Install dependencies" run: | - printenv BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK composer update ${{ env.COMPOSER_FLAGS }} - - name: "run unit tests" - run: "composer phpunit-run-integration-tests" \ No newline at end of file + - name: "Run integration tests" + run: | + printenv BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK + printenv + composer phpunit-run-integration-tests \ No newline at end of file From 3e81c1477ce8d8604f6d8d6cf008daf1c0d4d684 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 09:54:28 +0300 Subject: [PATCH 301/647] test ci\cd 14 Signed-off-by: mesilov --- .github/workflows/integration.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 44def89b..840902fc 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -22,11 +22,6 @@ jobs: dependencies: [ highest ] steps: - - name: "debug env" - run: | - echo " " - printenv BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK - printenv - name: "Checkout" uses: "actions/checkout@v2" From 21fdb73de4beb154b9986d538da4f703d7e10f16 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 09:56:24 +0300 Subject: [PATCH 302/647] test ci\cd 15 Signed-off-by: mesilov --- .github/workflows/integration.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 840902fc..ee7cd8fb 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -40,6 +40,5 @@ jobs: - name: "Run integration tests" run: | - printenv BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK printenv composer phpunit-run-integration-tests \ No newline at end of file From 29384e1bd979c595ac25dc73db6e7e7eb27a0854 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 10:02:19 +0300 Subject: [PATCH 303/647] test ci\cd 16 Signed-off-by: mesilov --- .github/workflows/integration.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index ee7cd8fb..f9739625 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -31,6 +31,7 @@ jobs: 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 }} @@ -41,4 +42,5 @@ jobs: - name: "Run integration tests" run: | printenv + printenv BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK composer phpunit-run-integration-tests \ No newline at end of file From 6bc607cf2c49499c7302c41eac41af93848f4e8b Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 10:07:19 +0300 Subject: [PATCH 304/647] test ci\cd 17 Signed-off-by: mesilov --- .github/workflows/integration.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index f9739625..3cbcc079 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -8,6 +8,8 @@ on: env: COMPOSER_FLAGS: "--ansi --no-interaction --no-progress --prefer-dist" + BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK: ${{ secrets.BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK }} + TEST2_ENV: 12345 jobs: tests: @@ -34,13 +36,16 @@ jobs: ini-values: variables_order=EGPCS env: BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK: ${{ secrets.BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK }} + TEST2_ENV: 12345 - name: "Install dependencies" run: | composer update ${{ env.COMPOSER_FLAGS }} - - name: "Run integration tests" + - name: "Debug ENV variables" run: | printenv - printenv BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK + + - name: "Run integration tests" + run: | composer phpunit-run-integration-tests \ No newline at end of file From 18fe6ccde3b9e77069e880799abf099638a56a17 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 10:13:23 +0300 Subject: [PATCH 305/647] test ci\cd 19 Signed-off-by: mesilov --- tests/Integration/Fabric.php | 1 - tests/bootstrap.php | 5 ++++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/Integration/Fabric.php b/tests/Integration/Fabric.php index 4c66602d..f1c791e8 100644 --- a/tests/Integration/Fabric.php +++ b/tests/Integration/Fabric.php @@ -51,7 +51,6 @@ public static function getCore(): CoreInterface print(print_r($_ENV, true)); print(print_r($_ENV['BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK'])); print(print_r($_ENV['BITRIX24_WEBHOOK'])); - exit(); return (new CoreBuilder()) ->withLogger(self::getLogger()) diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 11b8d641..60298e8b 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -22,4 +22,7 @@ (new Dotenv())->loadEnv(dirname(__DIR__) . '/tests/.env'); -phpinfo(); \ No newline at end of file + +print('ENV_VARS'); +print_r($_ENV); +print('ENV_VARS_END'); \ No newline at end of file From c80d58b6157fbb9d23c1b0a0ebc01b9cd5fca8f8 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 10:17:25 +0300 Subject: [PATCH 306/647] test ci\cd 20 Signed-off-by: mesilov --- tests/Integration/Fabric.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/Integration/Fabric.php b/tests/Integration/Fabric.php index f1c791e8..dcf0e876 100644 --- a/tests/Integration/Fabric.php +++ b/tests/Integration/Fabric.php @@ -47,11 +47,6 @@ public static function getBulkItemsReader(): BulkItemsReaderInterface */ public static function getCore(): CoreInterface { - - print(print_r($_ENV, true)); - print(print_r($_ENV['BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK'])); - print(print_r($_ENV['BITRIX24_WEBHOOK'])); - return (new CoreBuilder()) ->withLogger(self::getLogger()) ->withWebhookUrl($_ENV['BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK'] ?? $_ENV['BITRIX24_WEBHOOK']) From 055558671f34e845f73b752e1d60c82c37fe1a50 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 10:17:57 +0300 Subject: [PATCH 307/647] test ci\cd 21 Signed-off-by: mesilov --- tools/.env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/.env b/tools/.env index 7ad07ba6..635adce5 100644 --- a/tools/.env +++ b/tools/.env @@ -1,3 +1,3 @@ APP_ENV=dev LOGS_FILE=tools/logs/cli.log -LOGS_LEVEL=200 \ No newline at end of file +LOGS_LEVEL=300 \ No newline at end of file From 49e909b35b2a6f74c362108b6820ea25fdc1210b Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 10:24:10 +0300 Subject: [PATCH 308/647] fix debug in integration tests Signed-off-by: mesilov --- tests/bootstrap.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 60298e8b..ba8c63ba 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -20,9 +20,4 @@ putenv('APP_DEBUG=' . $_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = '0'); } -(new Dotenv())->loadEnv(dirname(__DIR__) . '/tests/.env'); - - -print('ENV_VARS'); -print_r($_ENV); -print('ENV_VARS_END'); \ No newline at end of file +(new Dotenv())->loadEnv(dirname(__DIR__) . '/tests/.env'); \ No newline at end of file From a317b12112b6a31a49987bbcaaf3d7da86dbb110 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 12:27:42 +0300 Subject: [PATCH 309/647] test ci\cd 22 Signed-off-by: mesilov --- .github/workflows/integration.yml | 12 +++++++++++- README.md | 10 ++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 3cbcc079..3f1922bd 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -48,4 +48,14 @@ jobs: - name: "Run integration tests" run: | - composer phpunit-run-integration-tests \ No newline at end of file + composer phpunit-run-integration-tests + + - name: "is integration tests succeeded" + if: ${{ success() }} + run: | + echo '✅ integration tests pass, congratulations!' + + - name: "is integration tests failed" + if: ${{ failure() }} + run: | + echo '::error:: ❗️teintegration tests failed' \ No newline at end of file diff --git a/README.md b/README.md index 3ef6188e..c725bb5a 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,14 @@ A powerful PHP library for the Bitrix24 REST API ### Build status -[![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) -[![phpunit 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) +| Master branch tests status | +|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| [![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 + ### BITRIX24-PHP-SDK Documentation From 6d78df89f800bf03ef120f4952cc614969b30246 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 12:33:44 +0300 Subject: [PATCH 310/647] test ci\cd 23 Signed-off-by: mesilov --- .github/workflows/integration.yml | 2 +- .github/workflows/phpstan.yml | 12 +++++++++++- .github/workflows/phpunit.yml | 12 +++++++++++- tests/Unit/Core/Result/AbstractItemTest.php | 9 +++++++++ 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 3f1922bd..667882f7 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -58,4 +58,4 @@ jobs: - name: "is integration tests failed" if: ${{ failure() }} run: | - echo '::error:: ❗️teintegration tests failed' \ No newline at end of file + echo '::error:: ❗️iteintegration tests failed ' \ No newline at end of file diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index 5b9859ae..2ced6c5b 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -40,4 +40,14 @@ jobs: run: "composer update --no-interaction --no-progress --no-suggest" - name: "PHPStan" - run: "composer phpstan-analyse" \ No newline at end of file + run: "composer phpstan-analyse" + + - name: "is PHPStan check succeeded" + if: ${{ success() }} + run: | + echo '✅ PHPStan check pass, congratulations!' + + - name: "is unit tests tests failed" + if: ${{ failure() }} + run: | + echo '::error:: ❗️ PHPStan check failed (╯°益°)╯彡┻━┻' \ No newline at end of file diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index f99825a2..725bb64a 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -34,4 +34,14 @@ jobs: composer update ${{ env.COMPOSER_FLAGS }} - name: "run unit tests" - run: "composer phpunit-run-unit-tests" \ No newline at end of file + run: "composer phpunit-run-unit-tests" + + - name: "is unit tests tests succeeded" + if: ${{ success() }} + run: | + echo '✅ unit tests pass, congratulations!' + + - name: "is unit tests tests failed" + if: ${{ failure() }} + run: | + echo '::error:: ❗️ unit tests tests failed (╯°益°)╯彡┻━┻' \ No newline at end of file diff --git a/tests/Unit/Core/Result/AbstractItemTest.php b/tests/Unit/Core/Result/AbstractItemTest.php index add2fef0..22c032f2 100644 --- a/tests/Unit/Core/Result/AbstractItemTest.php +++ b/tests/Unit/Core/Result/AbstractItemTest.php @@ -25,6 +25,7 @@ public function testSetPropertyItem(): void }; $testItem->ID = 2; } + /** * @covers \Bitrix24\SDK\Core\Result\AbstractItem::__unset */ @@ -35,4 +36,12 @@ public function testUnsetPropertyItem(): void }; unset($testItem->ID); } + + /** + * @covers \Bitrix24\SDK\Core\Result\AbstractItem::__unset + */ + public function testFailure(): void + { + $this->assertTrue(false); + } } \ No newline at end of file From d907fed56fa269ac58fecdaea6f6f92432e115fc Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 12:35:35 +0300 Subject: [PATCH 311/647] test ci\cd 24 Signed-off-by: mesilov --- .github/workflows/phpstan.yml | 2 +- tests/Unit/Core/Result/AbstractItemTest.php | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index 2ced6c5b..ea58e758 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -47,7 +47,7 @@ jobs: run: | echo '✅ PHPStan check pass, congratulations!' - - name: "is unit tests tests failed" + - name: "is PHPStan check failed" if: ${{ failure() }} run: | echo '::error:: ❗️ PHPStan check failed (╯°益°)╯彡┻━┻' \ No newline at end of file diff --git a/tests/Unit/Core/Result/AbstractItemTest.php b/tests/Unit/Core/Result/AbstractItemTest.php index 22c032f2..ce021874 100644 --- a/tests/Unit/Core/Result/AbstractItemTest.php +++ b/tests/Unit/Core/Result/AbstractItemTest.php @@ -36,12 +36,4 @@ public function testUnsetPropertyItem(): void }; unset($testItem->ID); } - - /** - * @covers \Bitrix24\SDK\Core\Result\AbstractItem::__unset - */ - public function testFailure(): void - { - $this->assertTrue(false); - } } \ No newline at end of file From 48165df9e28462943fe1280e7435fa2c91e38f24 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 12:43:07 +0300 Subject: [PATCH 312/647] test ci\cd 25 Signed-off-by: mesilov --- CHANGELOG.md | 1 + README.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 17153ef5..abd848e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ in `Bitrix24\SDK\Core\Response::__destruct()` * add `Bitrix24\SDK\Core\BulkItemsReader` for data-intensive applications for bulk export data from Bitrix24, read strategies located in folder `ReadStrategies`, in services read model **must** use most effective read strategy. +* add integration tests in GitHub Actions pipeline 🎉, now integration tests run on push on `dev-branch` ### Changed diff --git a/README.md b/README.md index c725bb5a..229f6baf 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ A powerful PHP library for the Bitrix24 REST API ### Build status -| Master branch tests status | +| CI\CD [status](https://github.com/mesilov/bitrix24-php-sdk/actions) | |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [![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) | From eabc270925970a65e73cac717b0c6747e8d41573 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Feb 2022 23:49:54 +0300 Subject: [PATCH 313/647] add ci\cd pipeline for vendor Signed-off-by: mesilov --- .github/workflows/integration.yml | 6 +-- .github/workflows/vendor-check.yml | 60 ++++++++++++++++++++++++++++++ CHANGELOG.md | 1 + README.md | 2 +- 4 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/vendor-check.yml diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 667882f7..4fa9ca09 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -50,12 +50,12 @@ jobs: run: | composer phpunit-run-integration-tests - - name: "is integration tests succeeded" + - name: "integration tests succeeded" if: ${{ success() }} run: | echo '✅ integration tests pass, congratulations!' - - name: "is integration tests failed" + - name: "integration tests failed" if: ${{ failure() }} run: | - echo '::error:: ❗️iteintegration tests failed ' \ No newline at end of file + echo '::error:: ❗️iteintegration tests failed (╯°益°)╯彡┻━┻ ' \ No newline at end of file diff --git a/.github/workflows/vendor-check.yml b/.github/workflows/vendor-check.yml new file mode 100644 index 00000000..de29fada --- /dev/null +++ b/.github/workflows/vendor-check.yml @@ -0,0 +1,60 @@ +name: "Vendor integration tests" + +on: + # run integration tests from vendor CI\CD pipeline with webhook + repository_dispatch: + types: [ run_vendor_integration_tests ] + +env: + COMPOSER_FLAGS: "--ansi --no-interaction --no-progress --prefer-dist" + BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK: ${{ secrets.BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK }} + TEST2_ENV: 12345 + +jobs: + tests: + name: "Vendor integration tests" + + runs-on: ubuntu-latest + + strategy: + matrix: + php-version: + - "7.4" + dependencies: [ highest ] + + steps: + + - name: "Checkout" + uses: "actions/checkout@v2" + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + coverage: "none" + php-version: "${{ matrix.php-version }}" + ini-values: variables_order=EGPCS + env: + BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK: ${{ secrets.BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK }} + TEST2_ENV: 12345 + + - name: "Install dependencies" + run: | + composer update ${{ env.COMPOSER_FLAGS }} + + - name: "Debug ENV variables" + run: | + printenv + + - name: "Run integration tests" + run: | + composer phpunit-run-integration-tests + + - name: "integration tests succeeded" + if: ${{ success() }} + run: | + echo '✅ integration tests pass, congratulations!' + + - name: "integration tests failed" + if: ${{ failure() }} + run: | + echo '::error:: ❗️iteintegration tests failed (╯°益°)╯彡┻━┻' \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index abd848e3..8ff37d69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ * add `Bitrix24\SDK\Core\BulkItemsReader` for data-intensive applications for bulk export data from Bitrix24, read strategies located in folder `ReadStrategies`, in services read model **must** use most effective read strategy. * add integration tests in GitHub Actions pipeline 🎉, now integration tests run on push on `dev-branch` +* add incoming webhook for run integration tests `vendor-check.yml` from vendor CI\CD pipeline ### Changed diff --git a/README.md b/README.md index 229f6baf..1b9bc9f7 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ A powerful PHP library for the Bitrix24 REST API ### Build status -| CI\CD [status](https://github.com/mesilov/bitrix24-php-sdk/actions) | +| 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) | From bc506db2781a9623e31df359fb051563177962a2 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 7 Feb 2022 00:30:35 +0300 Subject: [PATCH 314/647] bump CHANGELOG.md Signed-off-by: mesilov --- .github/workflows/integration.yml | 2 +- .github/workflows/vendor-check.yml | 2 +- CHANGELOG.md | 7 ++++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 4fa9ca09..0137cbe9 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -58,4 +58,4 @@ jobs: - name: "integration tests failed" if: ${{ failure() }} run: | - echo '::error:: ❗️iteintegration tests failed (╯°益°)╯彡┻━┻ ' \ No newline at end of file + echo '::error:: ❗integration tests failed (╯°益°)╯彡┻━┻ ' \ No newline at end of file diff --git a/.github/workflows/vendor-check.yml b/.github/workflows/vendor-check.yml index de29fada..2ec82413 100644 --- a/.github/workflows/vendor-check.yml +++ b/.github/workflows/vendor-check.yml @@ -57,4 +57,4 @@ jobs: - name: "integration tests failed" if: ${{ failure() }} run: | - echo '::error:: ❗️iteintegration tests failed (╯°益°)╯彡┻━┻' \ No newline at end of file + echo '::error:: ❗integration tests failed (╯°益°)╯彡┻━┻' \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ff37d69..b3c3de61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,12 @@ # bitrix24-php-sdk change log -## 2.0-alpha.6 — 20.01.2021 +## 2.0-alpha.6 — 7.02.2021 ### Added * add «fast» batch-query without counting elements in result - recordset [Добавить поддержку выгрузки большого количества данных без подсчёта элементов (-1](https://github.com/mesilov/bitrix24-php-sdk/issues/248) + recordset [Добавить поддержку выгрузки большого количества данных без подсчёта элементов -1](https://github.com/mesilov/bitrix24-php-sdk/issues/248) +* add `Credentials` in CoreBuilder [set credentials from core builder](https://github.com/mesilov/bitrix24-php-sdk/pull/246) * add method `Core\Batch::deleteEntityItems` for delete items in batch mode and integration test * add integration test for read strategy `FilterWithBatchWithoutCountOrderTest` * add type check in method `Core\Batch::deleteEntityItems` - only integer id allowed @@ -19,7 +20,7 @@ * add `Bitrix24\SDK\Core\BulkItemsReader` for data-intensive applications for bulk export data from Bitrix24, read strategies located in folder `ReadStrategies`, in services read model **must** use most effective read strategy. * add integration tests in GitHub Actions pipeline 🎉, now integration tests run on push on `dev-branch` -* add incoming webhook for run integration tests `vendor-check.yml` from vendor CI\CD pipeline +* add incoming webhook for run integration tests `vendor-check.yml` from vendor CI\CD pipeline ### Changed From 530a00a69150b62067efd1d9890ee21cef51b958 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 7 Feb 2022 01:13:21 +0300 Subject: [PATCH 315/647] update psr-log-package Signed-off-by: mesilov --- CHANGELOG.md | 1 + README.md | 2 +- composer.json | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3c3de61..aff9d94a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ * switch `symfony/http-client-contracts` to `^2.5` version requirement. * switch `symfony/event-dispatcher` to `5.4.*` version requirement. * switch `ramsey/uuid` to `^4.2.3` version requirement. +* switch `psr/log` to `^1.1.4 || ^2.0 || ^3.0` [version requirement](https://github.com/mesilov/bitrix24-php-sdk/issues/245). ## 2.0-alpha.5 – 28.11.2021 diff --git a/README.md b/README.md index 1b9bc9f7..2656f480 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -bitrix24-php-sdk – Bitrix24 REST API PHP SDK +Bitrix24 REST API PHP SDK ================ [![License](https://poser.pugx.org/mesilov/bitrix24-php-sdk/license.svg)](https://packagist.org/packages/mesilov/bitrix24-php-sdk) [![Total Downloads](https://poser.pugx.org/mesilov/bitrix24-php-sdk/downloads.svg)](https://packagist.org/packages/mesilov/bitrix24-php-sdk) [![Latest Stable Version](https://img.shields.io/packagist/v/mesilov/bitrix24-php-sdk.svg)](https://packagist.org/packages/mesilov/bitrix24-php-sdk) diff --git a/composer.json b/composer.json index 571dec6c..900ff842 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "php": "7.4.*|8.*", "ext-json": "*", "ext-curl": "*", - "psr/log": "1.1.3", + "psr/log": "^1.1.4 || ^2.0 || ^3.0", "fig/http-message-util": "1.1.*", "symfony/http-client": "5.4.*", "symfony/http-client-contracts": "^2.5", From 6f060a6a1e243cae6661be0df26e6d6e7477c800 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 2 May 2022 01:20:39 +0300 Subject: [PATCH 316/647] add batch support for update commands Signed-off-by: mesilov --- CHANGELOG.md | 9 ++ src/Core/Batch.php | 94 +++++++++++++++++-- src/Core/Contracts/BatchInterface.php | 11 ++- .../Contracts/UpdatedItemResultInterface.php | 15 +++ src/Core/Result/UpdatedItemBatchResult.php | 37 ++++++++ src/Services/CRM/Deal/Service/Batch.php | 28 +++++- .../Services/CRM/Deal/Service/BatchTest.php | 49 ++++++++++ tests/Unit/Stubs/NullBatch.php | 10 ++ 8 files changed, 241 insertions(+), 12 deletions(-) create mode 100644 src/Core/Contracts/UpdatedItemResultInterface.php create mode 100644 src/Core/Result/UpdatedItemBatchResult.php diff --git a/CHANGELOG.md b/CHANGELOG.md index aff9d94a..6e251d40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # bitrix24-php-sdk change log +## 2.0-alpha.7 — 2.05.2022 + +### Added + +* add method `Core\Batch::updateEntityItems` for [update items in batch mode](https://github.com/mesilov/bitrix24-php-sdk/issues/268) and integration test +* add method to interface `Core\Contracts\BatchInterface::updateEntityItems` for update items in batch mode +* add in scope «CRM» `Services\CRM\Deal\Service\Batch::update` batch update deals + + ## 2.0-alpha.6 — 7.02.2021 ### Added diff --git a/src/Core/Batch.php b/src/Core/Batch.php index 03379d3a..402d11b8 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -164,6 +164,83 @@ public function deleteEntityItems(string $apiMethod, array $entityItemId): Gener $this->logger->debug('deleteEntityItems.finish'); } + /** + * Update entity items with batch call + * + * Update elements in array with structure + * element_id => [ + * 'fields' => [], // required element fields to update + * 'params' => [] // optional fields + * ] + * + * @param string $apiMethod + * @param array $entityItems + * + * @return Generator|ResponseData[] + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function updateEntityItems(string $apiMethod, array $entityItems): Generator + { + $this->logger->debug( + 'updateEntityItems.start', + [ + 'apiMethod' => $apiMethod, + 'entityItems' => $entityItems, + ] + ); + + try { + $this->clearCommands(); + foreach ($entityItems as $entityItemId => $entityItem) { + if (!is_int($entityItemId)) { + throw new InvalidArgumentException( + sprintf( + 'invalid type «%s» of entity id «%s», entity id must be integer type', + gettype($entityItemId), + $entityItemId + ) + ); + } + if (!array_key_exists('fields', $entityItem)) { + throw new InvalidArgumentException( + sprintf('array key «fields» not found in entity item with id %s', $entityItemId) + ); + } + + $this->registerCommand($apiMethod, [ + 'id' => $entityItemId, + 'fields' => $entityItem['fields'], + 'params' => $entityItem['params'], + ]); + } + + foreach ($this->getTraversable(true) as $cnt => $updatedItemResult) { + yield $cnt => $updatedItemResult; + } + } catch (InvalidArgumentException $exception) { + $errorMessage = sprintf('batch update entity items: %s', $exception->getMessage()); + $this->logger->error( + $errorMessage, + [ + 'trace' => $exception->getTrace(), + ] + ); + throw $exception; + } catch (\Throwable $exception) { + $errorMessage = sprintf('batch update entity items: %s', $exception->getMessage()); + $this->logger->error( + $errorMessage, + [ + 'trace' => $exception->getTrace(), + ] + ); + + throw new BaseException($errorMessage, $exception->getCode(), $exception); + } + + $this->logger->debug('updateEntityItems.finish'); + } + /** * Register api command to command collection for batch calls * @@ -261,14 +338,15 @@ public function getTraversableList( array $select, ?int $limit = null ): Generator { - $this->logger->debug('getTraversableList.start', - [ - 'apiMethod' => $apiMethod, - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'limit' => $limit, - ] + $this->logger->debug( + 'getTraversableList.start', + [ + 'apiMethod' => $apiMethod, + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'limit' => $limit, + ] ); // strategy.3 — ID filter, batch, no count, order diff --git a/src/Core/Contracts/BatchInterface.php b/src/Core/Contracts/BatchInterface.php index d259a9d2..4a7f6c98 100644 --- a/src/Core/Contracts/BatchInterface.php +++ b/src/Core/Contracts/BatchInterface.php @@ -79,5 +79,14 @@ public function addEntityItems(string $apiMethod, array $entityItems): Generator */ public function deleteEntityItems(string $apiMethod, array $entityItemId): Generator; - //todo add updateEntityItems + /** + * Update entity items with batch call + * + * @param string $apiMethod + * @param array $entityItems + * + * @return Generator|ResponseData[] + * @throws BaseException + */ + public function updateEntityItems(string $apiMethod, array $entityItems): Generator; } \ No newline at end of file diff --git a/src/Core/Contracts/UpdatedItemResultInterface.php b/src/Core/Contracts/UpdatedItemResultInterface.php new file mode 100644 index 00000000..a1dda726 --- /dev/null +++ b/src/Core/Contracts/UpdatedItemResultInterface.php @@ -0,0 +1,15 @@ +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()->getResultData()[0]; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Service/Batch.php b/src/Services/CRM/Deal/Service/Batch.php index 81113517..e5351495 100644 --- a/src/Services/CRM/Deal/Service/Batch.php +++ b/src/Services/CRM/Deal/Service/Batch.php @@ -8,6 +8,7 @@ use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Result\AddedItemBatchResult; use Bitrix24\SDK\Core\Result\DeletedItemBatchResult; +use Bitrix24\SDK\Core\Result\UpdatedItemBatchResult; use Bitrix24\SDK\Services\CRM\Deal\Result\DealItemResult; use Generator; use Psr\Log\LoggerInterface; @@ -124,10 +125,10 @@ public function __construct(BatchInterface $batch, LoggerInterface $log) * UTM_CONTENT?: string, * UTM_TERM?: string, * } $filter - * @param array $select = ['ID','TITLE','TYPE_ID','CATEGORY_ID','STAGE_ID','STAGE_SEMANTIC_ID','IS_NEW','IS_RECURRING','IS_RETURN_CUSTOMER','IS_REPEATED_APPROACH','PROBABILITY','CURRENCY_ID','OPPORTUNITY','IS_MANUAL_OPPORTUNITY','TAX_VALUE','COMPANY_ID','CONTACT_ID','CONTACT_IDS','QUOTE_ID','BEGINDATE','CLOSEDATE','OPENED','CLOSED','COMMENTS','ASSIGNED_BY_ID','CREATED_BY_ID','MODIFY_BY_ID','DATE_CREATE','DATE_MODIFY','SOURCE_ID','SOURCE_DESCRIPTION','LEAD_ID','ADDITIONAL_INFO','LOCATION_ID','ORIGINATOR_ID','ORIGIN_ID','UTM_SOURCE','UTM_MEDIUM','UTM_CAMPAIGN','UTM_CONTENT','UTM_TERM'] - * @param int|null $limit + * @param array $select = ['ID','TITLE','TYPE_ID','CATEGORY_ID','STAGE_ID','STAGE_SEMANTIC_ID','IS_NEW','IS_RECURRING','IS_RETURN_CUSTOMER','IS_REPEATED_APPROACH','PROBABILITY','CURRENCY_ID','OPPORTUNITY','IS_MANUAL_OPPORTUNITY','TAX_VALUE','COMPANY_ID','CONTACT_ID','CONTACT_IDS','QUOTE_ID','BEGINDATE','CLOSEDATE','OPENED','CLOSED','COMMENTS','ASSIGNED_BY_ID','CREATED_BY_ID','MODIFY_BY_ID','DATE_CREATE','DATE_MODIFY','SOURCE_ID','SOURCE_DESCRIPTION','LEAD_ID','ADDITIONAL_INFO','LOCATION_ID','ORIGINATOR_ID','ORIGIN_ID','UTM_SOURCE','UTM_MEDIUM','UTM_CAMPAIGN','UTM_CONTENT','UTM_TERM'] + * @param int|null $limit * - * @return Generator + * @return Generator|DealItemResult[] * @throws BaseException */ public function list(array $order, array $filter, array $select, ?int $limit = null): Generator @@ -223,4 +224,25 @@ public function delete(array $dealId): Generator yield $key => new DeletedItemBatchResult($item); } } + + /** + * Update deals + * + * Update elements in array with structure + * element_id => [ // deal id + * 'fields' => [], // deal fields to update + * 'params' => [] + * ] + * + * @param array $entityItems + * + * @return \Generator + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function update(array $entityItems): Generator + { + foreach ($this->batch->updateEntityItems('crm.deal.update', $entityItems) as $key => $item) { + yield $key => new UpdatedItemBatchResult($item); + } + } } \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Deal/Service/BatchTest.php b/tests/Integration/Services/CRM/Deal/Service/BatchTest.php index f50524bb..08c19dbd 100644 --- a/tests/Integration/Services/CRM/Deal/Service/BatchTest.php +++ b/tests/Integration/Services/CRM/Deal/Service/BatchTest.php @@ -90,6 +90,55 @@ public function testBatchDelete(): void self::assertEquals(count($deals), $cnt); } + /** + * @testdox Batch delete deals + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\Batch::update() + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Exception + */ + public function testBatchUpdate(): void + { + // add deals + $deals = []; + for ($i = 1; $i < 60; $i++) { + $deals[] = ['TITLE' => 'TITLE-' . $i]; + } + $cnt = 0; + $dealId = []; + foreach ($this->dealService->batch->add($deals) as $item) { + $cnt++; + $dealId[] = $item->getId(); + } + self::assertEquals(count($deals), $cnt); + + // read deals and prepare update information + $dealsToUpdate = []; + $resultDeals = []; + foreach ($this->dealService->batch->list([], ['ID' => $dealId], ['ID', 'TITLE', 'OPPORTUNITY']) as $deal) { + $dealOpportunity = random_int(100, 10000); + $dealsToUpdate[$deal->ID] = [ + 'fields' => [ + 'OPPORTUNITY' => $dealOpportunity, + ], + 'params' => [], + ]; + $resultDeals[$deal->ID] = $dealOpportunity; + } + + // update deals + foreach ($this->dealService->batch->update($dealsToUpdate) as $dealUpdateResult) { + $this->assertTrue($dealUpdateResult->isSuccess()); + } + + // list deals + $updateResult = []; + foreach ($this->dealService->batch->list([], ['ID' => $dealId], ['ID', 'TITLE', 'OPPORTUNITY']) as $deal) { + $updateResult[$deal->ID] = $deal->OPPORTUNITY; + } + + $this->assertEquals($resultDeals, $updateResult); + } + public function setUp(): void { $this->dealService = Fabric::getServiceBuilder()->getCRMScope()->deal(); diff --git a/tests/Unit/Stubs/NullBatch.php b/tests/Unit/Stubs/NullBatch.php index efd8ab43..14ddbb6f 100644 --- a/tests/Unit/Stubs/NullBatch.php +++ b/tests/Unit/Stubs/NullBatch.php @@ -5,6 +5,8 @@ namespace Bitrix24\SDK\Tests\Unit\Stubs; use Bitrix24\SDK\Core\Contracts\BatchInterface; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Response\DTO\ResponseData; use Generator; /** @@ -51,4 +53,12 @@ public function deleteEntityItems(string $apiMethod, array $entityItemId): Gener { yield []; } + + /** + * @inheritDoc + */ + public function updateEntityItems(string $apiMethod, array $entityItems): Generator + { + yield []; + } } \ No newline at end of file From 404263d3ffd992e78d68f11953bb24b9c693364e Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 2 May 2022 14:58:06 +0300 Subject: [PATCH 317/647] update scope list Signed-off-by: mesilov --- CHANGELOG.md | 10 +++- src/Core/Credentials/Scope.php | 12 ++++- .../Services/Main/Service/MainTest.php | 46 +++++++++++++++++++ 3 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 tests/Integration/Services/Main/Service/MainTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index aff9d94a..8c502c40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ # bitrix24-php-sdk change log -## 2.0-alpha.6 — 7.02.2021 +## 2.0-alpha.7 — 02.05.2022 + + +### Changed +* update scope list [расширить и актуализировать доступные скоупы](https://github.com/mesilov/bitrix24-php-sdk/issues/280) + + + +## 2.0-alpha.6 — 7.02.2022 ### Added diff --git a/src/Core/Credentials/Scope.php b/src/Core/Credentials/Scope.php index 3ddda1fa..fbb6f5c9 100644 --- a/src/Core/Credentials/Scope.php +++ b/src/Core/Credentials/Scope.php @@ -17,11 +17,12 @@ class Scope * @var string[] */ protected array $availableScope = [ - 'app', 'bizproc', 'calendar', 'call', + 'cashbox', 'catalog', + 'configuration.import', 'contact_center', 'crm', 'delivery', @@ -31,6 +32,7 @@ class Scope 'entity', 'faceid', 'forum', + 'iblock', 'im', 'imbot', 'imopenlines', @@ -47,15 +49,23 @@ class Scope 'pull', 'pull_channel', 'rating', + 'rpa', 'sale', + 'salescenter', 'smile', + 'socialnetwork', 'sonet_group', 'task', + 'tasks', 'tasks_extended', 'telephony', 'timeman', 'user', + 'user.userfield', + 'user_basic', + 'user_brief', 'userconsent', + 'userfieldconfig', ]; /** diff --git a/tests/Integration/Services/Main/Service/MainTest.php b/tests/Integration/Services/Main/Service/MainTest.php new file mode 100644 index 00000000..6aaae2a1 --- /dev/null +++ b/tests/Integration/Services/Main/Service/MainTest.php @@ -0,0 +1,46 @@ +mainService->getAvailableScope()->getResponseData()->getResult()->getResultData()); + $this->assertIsArray($scope->getScopeCodes()); + } + + /** + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException + */ + public function testGetCurrentScope(): void + { + $this->assertGreaterThanOrEqual( + count((new Scope($this->mainService->getCurrentScope()->getResponseData()->getResult()->getResultData()))->getScopeCodes()), + count((new Scope($this->mainService->getAvailableScope()->getResponseData()->getResult()->getResultData()))->getScopeCodes()) + ); + } + + public function setUp(): void + { + $this->mainService = Fabric::getServiceBuilder()->getMainScope()->main(); + } +} \ No newline at end of file From 8f6a12b226eb4ad5453116c574eac43406a0ec57 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 2 May 2022 16:23:33 +0300 Subject: [PATCH 318/647] add lead support Signed-off-by: mesilov --- CHANGELOG.md | 7 +- src/Services/CRM/CRMServiceBuilder.php | 16 + .../CRM/Lead/Result/LeadItemResult.php | 81 ++++ src/Services/CRM/Lead/Result/LeadResult.php | 24 ++ src/Services/CRM/Lead/Result/LeadsResult.php | 31 ++ src/Services/CRM/Lead/Service/Batch.php | 226 +++++++++++ src/Services/CRM/Lead/Service/Lead.php | 357 ++++++++++++++++++ .../Services/CRM/Lead/Service/BatchTest.php | 97 +++++ .../Services/CRM/Lead/Service/LeadTest.php | 119 ++++++ 9 files changed, 957 insertions(+), 1 deletion(-) create mode 100644 src/Services/CRM/Lead/Result/LeadItemResult.php create mode 100644 src/Services/CRM/Lead/Result/LeadResult.php create mode 100644 src/Services/CRM/Lead/Result/LeadsResult.php create mode 100644 src/Services/CRM/Lead/Service/Batch.php create mode 100644 src/Services/CRM/Lead/Service/Lead.php create mode 100644 tests/Integration/Services/CRM/Lead/Service/BatchTest.php create mode 100644 tests/Integration/Services/CRM/Lead/Service/LeadTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index aff9d94a..c8c193cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # bitrix24-php-sdk change log -## 2.0-alpha.6 — 7.02.2021 +## 2.0-alpha.7 — 7.05.2022 + +### Added +* add `Leads` [добавить поддержку лидов](https://github.com/mesilov/bitrix24-php-sdk/issues/282) + +## 2.0-alpha.6 — 7.02.2022 ### Added diff --git a/src/Services/CRM/CRMServiceBuilder.php b/src/Services/CRM/CRMServiceBuilder.php index 82b5040e..25d7709f 100644 --- a/src/Services/CRM/CRMServiceBuilder.php +++ b/src/Services/CRM/CRMServiceBuilder.php @@ -170,4 +170,20 @@ public function userfield(): Userfield\Service\Userfield return $this->serviceCache[__METHOD__]; } + + /** + * @return Lead\Service\Lead + */ + public function lead(): Lead\Service\Lead + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Lead\Service\Lead( + new Lead\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } } \ No newline at end of file diff --git a/src/Services/CRM/Lead/Result/LeadItemResult.php b/src/Services/CRM/Lead/Result/LeadItemResult.php new file mode 100644 index 00000000..ab26d91c --- /dev/null +++ b/src/Services/CRM/Lead/Result/LeadItemResult.php @@ -0,0 +1,81 @@ +getKeyWithUserfieldByFieldName($userfieldName); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Lead/Result/LeadResult.php b/src/Services/CRM/Lead/Result/LeadResult.php new file mode 100644 index 00000000..7e476650 --- /dev/null +++ b/src/Services/CRM/Lead/Result/LeadResult.php @@ -0,0 +1,24 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData()); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Lead/Result/LeadsResult.php b/src/Services/CRM/Lead/Result/LeadsResult.php new file mode 100644 index 00000000..77131b48 --- /dev/null +++ b/src/Services/CRM/Lead/Result/LeadsResult.php @@ -0,0 +1,31 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { + $items[] = new LeadItemResult($item); + } + + return $items; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Lead/Service/Batch.php b/src/Services/CRM/Lead/Service/Batch.php new file mode 100644 index 00000000..934457c5 --- /dev/null +++ b/src/Services/CRM/Lead/Service/Batch.php @@ -0,0 +1,226 @@ +batch = $batch; + $this->log = $log; + } + + /** + * Batch list method for leads + * + * @param array{ + * ID?: string, + * TITLE?: string, + * TYPE_ID?: string, + * CATEGORY_ID?: string, + * STAGE_ID?: string, + * STAGE_SEMANTIC_ID?: string, + * IS_NEW?: string, + * IS_RECURRING?: string, + * IS_RETURN_CUSTOMER?: string, + * IS_REPEATED_APPROACH?: string, + * PROBABILITY?: string, + * CURRENCY_ID?: string, + * OPPORTUNITY?: string, + * IS_MANUAL_OPPORTUNITY?: string, + * TAX_VALUE?: string, + * COMPANY_ID?: string, + * CONTACT_ID?: string, + * CONTACT_IDS?: string, + * QUOTE_ID?: string, + * BEGINDATE?: string, + * CLOSEDATE?: string, + * OPENED?: string, + * CLOSED?: string, + * COMMENTS?: string, + * ASSIGNED_BY_ID?: string, + * CREATED_BY_ID?: string, + * MODIFY_BY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: string, + * LEAD_ID?: string, + * ADDITIONAL_INFO?: string, + * LOCATION_ID?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string, + * } $order + * + * @param array{ + * ID?: int, + * TITLE?: string, + * TYPE_ID?: string, + * CATEGORY_ID?: string, + * STAGE_ID?: string, + * STAGE_SEMANTIC_ID?: string, + * IS_NEW?: string, + * IS_RECURRING?: string, + * IS_RETURN_CUSTOMER?: string, + * IS_REPEATED_APPROACH?: string, + * PROBABILITY?: int, + * CURRENCY_ID?: string, + * OPPORTUNITY?: string, + * IS_MANUAL_OPPORTUNITY?: string, + * TAX_VALUE?: string, + * COMPANY_ID?: string, + * CONTACT_ID?: string, + * CONTACT_IDS?: string, + * QUOTE_ID?: string, + * BEGINDATE?: string, + * CLOSEDATE?: string, + * OPENED?: string, + * CLOSED?: string, + * COMMENTS?: string, + * ASSIGNED_BY_ID?: string, + * CREATED_BY_ID?: string, + * MODIFY_BY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: string, + * LEAD_ID?: string, + * ADDITIONAL_INFO?: string, + * LOCATION_ID?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string, + * } $filter + * @param array $select = ['ID','TITLE','TYPE_ID','CATEGORY_ID','STAGE_ID','STAGE_SEMANTIC_ID','IS_NEW','IS_RECURRING','IS_RETURN_CUSTOMER','IS_REPEATED_APPROACH','PROBABILITY','CURRENCY_ID','OPPORTUNITY','IS_MANUAL_OPPORTUNITY','TAX_VALUE','COMPANY_ID','CONTACT_ID','CONTACT_IDS','QUOTE_ID','BEGINDATE','CLOSEDATE','OPENED','CLOSED','COMMENTS','ASSIGNED_BY_ID','CREATED_BY_ID','MODIFY_BY_ID','DATE_CREATE','DATE_MODIFY','SOURCE_ID','SOURCE_DESCRIPTION','LEAD_ID','ADDITIONAL_INFO','LOCATION_ID','ORIGINATOR_ID','ORIGIN_ID','UTM_SOURCE','UTM_MEDIUM','UTM_CAMPAIGN','UTM_CONTENT','UTM_TERM'] + * @param int|null $limit + * + * @return Generator + * @throws BaseException + */ + public function list(array $order, array $filter, array $select, ?int $limit = null): Generator + { + $this->log->debug( + 'batchList', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'limit' => $limit, + ] + ); + foreach ($this->batch->getTraversableList('crm.lead.list', $order, $filter, $select, $limit) as $key => $value) { + yield $key => new DealItemResult($value); + } + } + + /** + * Batch adding leads + * + * @param array $leads + * + * @return Generator|AddedItemBatchResult[] + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function add(array $leads): Generator + { + $items = []; + foreach ($leads as $lead) { + $items[] = [ + 'fields' => $lead, + ]; + } + foreach ($this->batch->addEntityItems('crm.lead.add', $items) as $key => $item) { + yield $key => new AddedItemBatchResult($item); + } + } + + /** + * Batch delete leads + * + * @param int[] $leadId + * + * @return \Generator|\Bitrix24\SDK\Core\Contracts\DeletedItemResultInterface[] + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function delete(array $leadId): Generator + { + foreach ($this->batch->deleteEntityItems('crm.lead.delete', $leadId) as $key => $item) { + yield $key => new DeletedItemBatchResult($item); + } + } +} \ No newline at end of file diff --git a/src/Services/CRM/Lead/Service/Lead.php b/src/Services/CRM/Lead/Service/Lead.php new file mode 100644 index 00000000..808a5b63 --- /dev/null +++ b/src/Services/CRM/Lead/Service/Lead.php @@ -0,0 +1,357 @@ +batch = $batch; + } + + /** + * add new lead + * + * @link https://training.bitrix24.com/rest_help/crm/leads/crm_lead_add.php + * + * @param array{ + * ID?: int, + * TITLE?: string, + * HONORIFIC?: string, + * NAME?: string, + * SECOND_NAME?: string, + * LAST_NAME?: string, + * BIRTHDATE?: string, + * COMPANY_TITLE?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: string, + * STATUS_ID?: string, + * STATUS_DESCRIPTION?: string, + * STATUS_SEMANTIC_ID?: string, + * POST?: string, + * ADDRESS?: string, + * ADDRESS_2?: string, + * ADDRESS_CITY?: string, + * ADDRESS_POSTAL_CODE?: string, + * ADDRESS_REGION?: string, + * ADDRESS_PROVINCE?: string, + * ADDRESS_COUNTRY?: string, + * ADDRESS_COUNTRY_CODE?: string, + * ADDRESS_LOC_ADDR_ID?: int, + * CURRENCY_ID?: string, + * OPPORTUNITY?: string, + * IS_MANUAL_OPPORTUNITY?: string, + * OPENED?: string, + * COMMENTS?: string, + * HAS_PHONE?: string, + * HAS_EMAIL?: string, + * HAS_IMOL?: string, + * ASSIGNED_BY_ID?: string, + * CREATED_BY_ID?: string, + * MODIFY_BY_ID?: string, + * MOVED_BY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * MOVED_TIME?: string, + * COMPANY_ID?: string, + * CONTACT_ID?: string, + * CONTACT_IDS?: string, + * IS_RETURN_CUSTOMER?: string, + * DATE_CLOSED?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string, + * PHONE?: string, + * EMAIL?: string, + * WEB?: string, + * IM?: string, + * LINK?: string + * } $fields + * + * @param array{ + * REGISTER_SONET_EVENT?: string + * } $params + * + * @return AddedItemResult + * @throws BaseException + * @throws TransportException + */ + public function add(array $fields, array $params = []): AddedItemResult + { + return new AddedItemResult( + $this->core->call( + 'crm.lead.add', + [ + 'fields' => $fields, + 'params' => $params, + ] + ) + ); + } + + /** + * Deletes the specified lead and all the associated objects. + * + * @link https://training.bitrix24.com/rest_help/crm/leads/crm_lead_delete.php + * + * @param int $id + * + * @return DeletedItemResult + * @throws BaseException + * @throws TransportException + */ + public function delete(int $id): DeletedItemResult + { + return new DeletedItemResult( + $this->core->call( + 'crm.lead.delete', + [ + 'id' => $id, + ] + ) + ); + } + + /** + * Returns the description of the lead fields, including user fields. + * + * @link https://training.bitrix24.com/rest_help/crm/leads/crm_lead_fields.php + * + * @return FieldsResult + * @throws BaseException + * @throws TransportException + */ + public function fields(): FieldsResult + { + return new FieldsResult($this->core->call('crm.lead.fields')); + } + + /** + * Returns a lead by the lead ID. + * + * @link https://training.bitrix24.com/rest_help/crm/leads/crm_lead_get.php + * + * @param int $id + * + * @return LeadResult + * @throws BaseException + * @throws TransportException + */ + public function get(int $id): LeadResult + { + return new LeadResult($this->core->call('crm.lead.get', ['id' => $id])); + } + + /** + * Get list of lead items. + * + * @link https://training.bitrix24.com/rest_help/crm/leads/crm_lead_list.php + * + * @param array $order - order of lead items + * @param array $filter - filter array + * @param array $select = ['ID','TITLE','HONORIFIC','NAME','SECOND_NAME','LAST_NAME','BIRTHDATE','COMPANY_TITLE','SOURCE_ID','SOURCE_DESCRIPTION','STATUS_ID','STATUS_DESCRIPTION','STATUS_SEMANTIC_ID','POST','ADDRESS','ADDRESS_2','ADDRESS_CITY','ADDRESS_POSTAL_CODE','ADDRESS_REGION','ADDRESS_PROVINCE','ADDRESS_COUNTRY','ADDRESS_COUNTRY_CODE','ADDRESS_LOC_ADDR_ID','CURRENCY_ID','OPPORTUNITY','IS_MANUAL_OPPORTUNITY','OPENED','COMMENTS','HAS_PHONE','HAS_EMAIL','HAS_IMOL','ASSIGNED_BY_ID','CREATED_BY_ID','MODIFY_BY_ID','MOVED_BY_ID','DATE_CREATE','DATE_MODIFY','MOVED_TIME','COMPANY_ID','CONTACT_ID','CONTACT_IDS','IS_RETURN_CUSTOMER','DATE_CLOSED','ORIGINATOR_ID','ORIGIN_ID','UTM_SOURCE','UTM_MEDIUM','UTM_CAMPAIGN','UTM_CONTENT','UTM_TERM','PHONE','EMAIL','WEB','IM','LINK'] + * @param integer $startItem - entity number to start from (usually returned in 'next' field of previous 'crm.lead.list' API call) + * + * @throws BaseException + * @throws TransportException + * @return LeadsResult + */ + public function list(array $order, array $filter, array $select, int $startItem = 0): LeadsResult + { + return new LeadsResult( + $this->core->call( + 'crm.lead.list', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $startItem, + ] + ) + ); + } + + /** + * Updates the specified (existing) lead. + * + * @link https://training.bitrix24.com/rest_help/crm/leads/crm_lead_update.php + * + * @param int $id + * @param array{ + * ID?: int, + * TITLE?: string, + * HONORIFIC?: string, + * NAME?: string, + * SECOND_NAME?: string, + * LAST_NAME?: string, + * BIRTHDATE?: string, + * COMPANY_TITLE?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: string, + * STATUS_ID?: string, + * STATUS_DESCRIPTION?: string, + * STATUS_SEMANTIC_ID?: string, + * POST?: string, + * ADDRESS?: string, + * ADDRESS_2?: string, + * ADDRESS_CITY?: string, + * ADDRESS_POSTAL_CODE?: string, + * ADDRESS_REGION?: string, + * ADDRESS_PROVINCE?: string, + * ADDRESS_COUNTRY?: string, + * ADDRESS_COUNTRY_CODE?: string, + * ADDRESS_LOC_ADDR_ID?: int, + * CURRENCY_ID?: string, + * OPPORTUNITY?: string, + * IS_MANUAL_OPPORTUNITY?: string, + * OPENED?: string, + * COMMENTS?: string, + * HAS_PHONE?: string, + * HAS_EMAIL?: string, + * HAS_IMOL?: string, + * ASSIGNED_BY_ID?: string, + * CREATED_BY_ID?: string, + * MODIFY_BY_ID?: string, + * MOVED_BY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * MOVED_TIME?: string, + * COMPANY_ID?: string, + * CONTACT_ID?: string, + * CONTACT_IDS?: string, + * IS_RETURN_CUSTOMER?: string, + * DATE_CLOSED?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string, + * PHONE?: string, + * EMAIL?: string, + * WEB?: string, + * IM?: string, + * LINK?: string + * } $fields + * + * @param array{ + * REGISTER_SONET_EVENT?: string + * } $params + * + * @return UpdatedItemResult + * @throws BaseException + * @throws TransportException + */ + public function update(int $id, array $fields, array $params = []): UpdatedItemResult + { + return new UpdatedItemResult( + $this->core->call( + 'crm.lead.update', + [ + 'id' => $id, + 'fields' => $fields, + 'params' => $params, + ] + ) + ); + } + + /** + * Count leads by filter + * + * @param array{ + * ID?: int, + * TITLE?: string, + * HONORIFIC?: string, + * NAME?: string, + * SECOND_NAME?: string, + * LAST_NAME?: string, + * BIRTHDATE?: string, + * COMPANY_TITLE?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: string, + * STATUS_ID?: string, + * STATUS_DESCRIPTION?: string, + * STATUS_SEMANTIC_ID?: string, + * POST?: string, + * ADDRESS?: string, + * ADDRESS_2?: string, + * ADDRESS_CITY?: string, + * ADDRESS_POSTAL_CODE?: string, + * ADDRESS_REGION?: string, + * ADDRESS_PROVINCE?: string, + * ADDRESS_COUNTRY?: string, + * ADDRESS_COUNTRY_CODE?: string, + * ADDRESS_LOC_ADDR_ID?: int, + * CURRENCY_ID?: string, + * OPPORTUNITY?: string, + * IS_MANUAL_OPPORTUNITY?: string, + * OPENED?: string, + * COMMENTS?: string, + * HAS_PHONE?: string, + * HAS_EMAIL?: string, + * HAS_IMOL?: string, + * ASSIGNED_BY_ID?: string, + * CREATED_BY_ID?: string, + * MODIFY_BY_ID?: string, + * MOVED_BY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * MOVED_TIME?: string, + * COMPANY_ID?: string, + * CONTACT_ID?: string, + * CONTACT_IDS?: string, + * IS_RETURN_CUSTOMER?: string, + * DATE_CLOSED?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string, + * PHONE?: string, + * EMAIL?: string, + * WEB?: string, + * IM?: string, + * LINK?: string + * } $filter + * + * @return int + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function countByFilter(array $filter = []): int + { + return $this->list([], $filter, ['ID'], 1)->getCoreResponse()->getResponseData()->getPagination()->getTotal(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Lead/Service/BatchTest.php b/tests/Integration/Services/CRM/Lead/Service/BatchTest.php new file mode 100644 index 00000000..8792fab2 --- /dev/null +++ b/tests/Integration/Services/CRM/Lead/Service/BatchTest.php @@ -0,0 +1,97 @@ +leadService->add(['TITLE' => 'test lead'])->getId(); + $cnt = 0; + + foreach ($this->leadService->batch->list([], ['ID' => $itemId], ['ID', 'NAME'], 1) as $item) { + $cnt++; + } + self::assertGreaterThanOrEqual(1, $cnt); + + $this->leadService->delete($itemId); + } + + /** + * @testdox Batch add lead + * @covers \Bitrix24\SDK\Services\CRM\Lead\Service\Batch::add() + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function testBatchAdd(): void + { + $items = []; + for ($i = 1; $i < 60; $i++) { + $items[] = ['TITLE' => 'TITLE-' . $i]; + } + $cnt = 0; + $itemId = []; + foreach ($this->leadService->batch->add($items) as $item) { + $cnt++; + $itemId[] = $item->getId(); + } + self::assertEquals(count($items), $cnt); + + $cnt = 0; + foreach ($this->leadService->batch->delete($itemId) as $cnt => $deleteResult) { + $cnt++; + } + self::assertEquals(count($items), $cnt); + } + + /** + * @testdox Batch delete deals + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\Batch::add() + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function testBatchDelete(): void + { + $deals = []; + for ($i = 1; $i < 60; $i++) { + $deals[] = ['TITLE' => 'TITLE-' . $i]; + } + $cnt = 0; + $dealId = []; + foreach ($this->leadService->batch->add($deals) as $item) { + $cnt++; + $dealId[] = $item->getId(); + } + self::assertEquals(count($deals), $cnt); + + $cnt = 0; + foreach ($this->leadService->batch->delete($dealId) as $cnt => $deleteResult) { + $cnt++; + } + self::assertEquals(count($deals), $cnt); + } + + public function setUp(): void + { + $this->leadService = Fabric::getServiceBuilder()->getCRMScope()->lead(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Lead/Service/LeadTest.php b/tests/Integration/Services/CRM/Lead/Service/LeadTest.php new file mode 100644 index 00000000..9891e483 --- /dev/null +++ b/tests/Integration/Services/CRM/Lead/Service/LeadTest.php @@ -0,0 +1,119 @@ +leadService->add(['TITLE' => 'test lead'])->getId()); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers Lead::delete + */ + public function testDelete(): void + { + self::assertTrue($this->leadService->delete($this->leadService->add(['TITLE' => 'test lead'])->getId())->isSuccess()); + } + + /** + * @covers Lead::fields + * @throws BaseException + * @throws TransportException + */ + public function testFields(): void + { + self::assertIsArray($this->leadService->fields()->getFieldsDescription()); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers Lead::get + */ + public function testGet(): void + { + self::assertGreaterThan( + 1, + $this->leadService->get($this->leadService->add(['TITLE' => 'test Lead'])->getId())->lead()->ID + ); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers Lead::list + */ + public function testList(): void + { + $this->leadService->add(['TITLE' => 'test']); + self::assertGreaterThanOrEqual(1, $this->leadService->list([], [], ['ID', 'TITLE'])->getLeads()); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers Lead::update + */ + public function testUpdate(): void + { + $deal = $this->leadService->add(['TITLE' => 'test lead']); + $newTitle = 'test2'; + + self::assertTrue($this->leadService->update($deal->getId(), ['TITLE' => $newTitle], [])->isSuccess()); + self::assertEquals($newTitle, $this->leadService->get($deal->getId())->lead()->TITLE); + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\Deal::countByFilter + */ + public function testCountByFilter(): void + { + $before = $this->leadService->countByFilter(); + + $newItemsCount = 60; + $items = []; + for ($i = 1; $i <= $newItemsCount; $i++) { + $items[] = ['TITLE' => 'TITLE-' . $i]; + } + $cnt = 0; + foreach ($this->leadService->batch->add($items) as $item) { + $cnt++; + } + self::assertEquals(count($items), $cnt); + + $after = $this->leadService->countByFilter(); + + $this->assertEquals($before + $newItemsCount, $after); + } + + public function setUp(): void + { + $this->leadService = Fabric::getServiceBuilder()->getCRMScope()->lead(); + } +} \ No newline at end of file From 46764d3ec81d6c6640c0fd8f8f4414c1edaa8f5c Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 7 May 2022 01:31:15 +0300 Subject: [PATCH 319/647] batch bugfix Signed-off-by: mesilov --- src/Core/Batch.php | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/Core/Batch.php b/src/Core/Batch.php index 03379d3a..f588622a 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -261,14 +261,15 @@ public function getTraversableList( array $select, ?int $limit = null ): Generator { - $this->logger->debug('getTraversableList.start', - [ - 'apiMethod' => $apiMethod, - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'limit' => $limit, - ] + $this->logger->debug( + 'getTraversableList.start', + [ + 'apiMethod' => $apiMethod, + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'limit' => $limit, + ] ); // strategy.3 — ID filter, batch, no count, order @@ -298,7 +299,6 @@ public function getTraversableList( // todo проверили, что если есть limit, то он >1 // todo проверили, что в фильтре нет поля ID, т.к. мы с ним будем работать - $firstResultPage = $this->core->call( $apiMethod, [ @@ -309,6 +309,9 @@ public function getTraversableList( ] ); $totalElementsCount = $firstResultPage->getResponseData()->getPagination()->getTotal(); + $this->logger->debug('getTraversableList.totalElementsCount', [ + 'totalElementsCount' => $totalElementsCount, + ]); // filtered elements count less than or equal one result page(50 elements) $elementsCounter = 0; if ($totalElementsCount <= self::MAX_ELEMENTS_IN_PAGE) { @@ -329,7 +332,7 @@ public function getTraversableList( $lastElementIdInFirstPage = null; foreach ($firstResultPage->getResponseData()->getResult()->getResultData() as $cnt => $listElement) { $elementsCounter++; - $lastElementIdInFirstPage = $listElement['ID']; + $lastElementIdInFirstPage = (int)$listElement['ID']; if ($limit !== null && $elementsCounter > $limit) { return; } @@ -351,8 +354,17 @@ public function getTraversableList( 'start' => 0, ] ); - $lastElementId = (int)$lastResultPage->getResponseData()->getResult()->getResultData()[0]['ID']; + // reverse order if you need + if ($lastElementIdInFirstPage > $lastElementId) { + $tmp = $lastElementIdInFirstPage; + $lastElementIdInFirstPage = $lastElementId; + $lastElementId = $tmp; + } + $this->logger->debug('getTraversableList.lastElementsId', [ + 'lastElementIdInFirstPage' => $lastElementIdInFirstPage, + 'lastElementId' => $lastElementId, + ]); // register commands with updated filter //more than one page in results - register list commands From e447738af4f5327527689b3302163edf4a83783e Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 7 May 2022 01:31:56 +0300 Subject: [PATCH 320/647] add activity support Signed-off-by: mesilov --- CHANGELOG.md | 13 +- .../CRM/Activity/Result/ActivitiesResult.php | 26 ++ .../Activity/Result/ActivityItemResult.php | 59 +++ .../CRM/Activity/Result/ActivityResult.php | 16 + .../CRM/Activity/Service/Activity.php | 413 ++++++++++++++++++ src/Services/CRM/Activity/Service/Batch.php | 216 +++++++++ src/Services/CRM/CRMServiceBuilder.php | 16 + src/Services/CRM/Contact/Service/Batch.php | 24 +- .../CRM/Activity/Service/ActivityTest.php | 267 +++++++++++ .../CRM/Activity/Service/BatchTest.php | 189 ++++++++ 10 files changed, 1234 insertions(+), 5 deletions(-) create mode 100644 src/Services/CRM/Activity/Result/ActivitiesResult.php create mode 100644 src/Services/CRM/Activity/Result/ActivityItemResult.php create mode 100644 src/Services/CRM/Activity/Result/ActivityResult.php create mode 100644 src/Services/CRM/Activity/Service/Activity.php create mode 100644 src/Services/CRM/Activity/Service/Batch.php create mode 100644 tests/Integration/Services/CRM/Activity/Service/ActivityTest.php create mode 100644 tests/Integration/Services/CRM/Activity/Service/BatchTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index aff9d94a..6c5ac0f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,17 @@ # bitrix24-php-sdk change log -## 2.0-alpha.6 — 7.02.2021 +## 2.0-alpha.7 — 7.05.2022 + +### Added + +* add CRM Activity support [добавить поддержку дел](https://github.com/mesilov/bitrix24-php-sdk/issues/283) +* add in scope «CRM» `Services\CRM\Contact\Service\Batch::delete` batch delete contacts + +### Bugfix + +* add bugfix for batch method for reverse order queries + +## 2.0-alpha.6 — 7.02.2022 ### Added diff --git a/src/Services/CRM/Activity/Result/ActivitiesResult.php b/src/Services/CRM/Activity/Result/ActivitiesResult.php new file mode 100644 index 00000000..1eef454a --- /dev/null +++ b/src/Services/CRM/Activity/Result/ActivitiesResult.php @@ -0,0 +1,26 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { + $res[] = new ActivityItemResult($item); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/Result/ActivityItemResult.php b/src/Services/CRM/Activity/Result/ActivityItemResult.php new file mode 100644 index 00000000..d7fecbfb --- /dev/null +++ b/src/Services/CRM/Activity/Result/ActivityItemResult.php @@ -0,0 +1,59 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData()); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/Service/Activity.php b/src/Services/CRM/Activity/Service/Activity.php new file mode 100644 index 00000000..9ccde4f7 --- /dev/null +++ b/src/Services/CRM/Activity/Service/Activity.php @@ -0,0 +1,413 @@ +batch = $batch; + } + + /** + * Creates and adds a new activity. + * + * @link https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_add.php + * + * @param array{ + * ID?: int, + * OWNER_ID?: int, + * OWNER_TYPE_ID?: string, + * TYPE_ID?: string, + * PROVIDER_ID?: string, + * PROVIDER_TYPE_ID?: string, + * PROVIDER_GROUP_ID?: string, + * ASSOCIATED_ENTITY_ID?: int, + * SUBJECT?: string, + * START_TIME?: string, + * END_TIME?: string, + * DEADLINE?: string, + * COMPLETED?: string, + * STATUS?: string, + * RESPONSIBLE_ID?: string, + * PRIORITY?: string, + * NOTIFY_TYPE?: string, + * NOTIFY_VALUE?: int, + * DESCRIPTION?: string, + * DESCRIPTION_TYPE?: string, + * DIRECTION?: string, + * LOCATION?: string, + * CREATED?: string, + * AUTHOR_ID?: string, + * LAST_UPDATED?: string, + * EDITOR_ID?: string, + * SETTINGS?: string, + * ORIGIN_ID?: string, + * ORIGINATOR_ID?: string, + * RESULT_STATUS?: int, + * RESULT_STREAM?: int, + * RESULT_SOURCE_ID?: string, + * PROVIDER_PARAMS?: string, + * PROVIDER_DATA?: string, + * RESULT_MARK?: int, + * RESULT_VALUE?: string, + * RESULT_SUM?: string, + * RESULT_CURRENCY_ID?: string, + * AUTOCOMPLETE_RULE?: int, + * BINDINGS?: string, + * COMMUNICATIONS?: string, + * FILES?: string, + * WEBDAV_ELEMENTS?: string, + * } $fields + * + * @return AddedItemResult + * @throws BaseException + * @throws TransportException + */ + public function add(array $fields): AddedItemResult + { + return new AddedItemResult( + $this->core->call( + 'crm.activity.add', + [ + 'fields' => $fields, + ] + ) + ); + } + + /** + * Deletes the specified activity and all the associated objects. + * + * @link https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_delete.php + * + * @param int $itemId + * + * @return DeletedItemResult + * @throws BaseException + * @throws TransportException + */ + public function delete(int $itemId): DeletedItemResult + { + return new DeletedItemResult( + $this->core->call( + 'crm.activity.delete', + [ + 'id' => $itemId, + ] + ) + ); + } + + /** + * Returns the description of activity + * + * @link https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_fields.php + * + * @return FieldsResult + * @throws BaseException + * @throws TransportException + */ + public function fields(): FieldsResult + { + return new FieldsResult($this->core->call('crm.activity.fields')); + } + + /** + * Returns activity by the specified activity ID + * + * @link https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_get.php + * + * @param int $entityId + * + * @return ActivityResult + * @throws BaseException + * @throws TransportException + */ + public function get(int $entityId): ActivityResult + { + return new ActivityResult( + $this->core->call( + 'crm.activity.get', + [ + 'id' => $entityId, + ] + ) + ); + } + + /** + * Returns a list of activity selected by the filter specified as the parameter. See the example for the filter notation. + * + * @link https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_list.php + * + * @param array{ + * ID?: int, + * OWNER_ID?: int, + * OWNER_TYPE_ID?: string, + * TYPE_ID?: string, + * PROVIDER_ID?: string, + * PROVIDER_TYPE_ID?: string, + * PROVIDER_GROUP_ID?: string, + * ASSOCIATED_ENTITY_ID?: int, + * SUBJECT?: string, + * START_TIME?: string, + * END_TIME?: string, + * DEADLINE?: string, + * COMPLETED?: string, + * STATUS?: string, + * RESPONSIBLE_ID?: string, + * PRIORITY?: string, + * NOTIFY_TYPE?: string, + * NOTIFY_VALUE?: int, + * DESCRIPTION?: string, + * DESCRIPTION_TYPE?: string, + * DIRECTION?: string, + * LOCATION?: string, + * CREATED?: string, + * AUTHOR_ID?: string, + * LAST_UPDATED?: string, + * EDITOR_ID?: string, + * SETTINGS?: string, + * ORIGIN_ID?: string, + * ORIGINATOR_ID?: string, + * RESULT_STATUS?: int, + * RESULT_STREAM?: int, + * RESULT_SOURCE_ID?: string, + * PROVIDER_PARAMS?: string, + * PROVIDER_DATA?: string, + * RESULT_MARK?: int, + * RESULT_VALUE?: string, + * RESULT_SUM?: string, + * RESULT_CURRENCY_ID?: string, + * AUTOCOMPLETE_RULE?: int, + * BINDINGS?: string, + * COMMUNICATIONS?: string, + * FILES?: string, + * WEBDAV_ELEMENTS?: string, + * } $order + * + * @param array{ + * ID?: int, + * OWNER_ID?: int, + * OWNER_TYPE_ID?: string, + * TYPE_ID?: string, + * PROVIDER_ID?: string, + * PROVIDER_TYPE_ID?: string, + * PROVIDER_GROUP_ID?: string, + * ASSOCIATED_ENTITY_ID?: int, + * SUBJECT?: string, + * START_TIME?: string, + * END_TIME?: string, + * DEADLINE?: string, + * COMPLETED?: string, + * STATUS?: string, + * RESPONSIBLE_ID?: string, + * PRIORITY?: string, + * NOTIFY_TYPE?: string, + * NOTIFY_VALUE?: int, + * DESCRIPTION?: string, + * DESCRIPTION_TYPE?: string, + * DIRECTION?: string, + * LOCATION?: string, + * CREATED?: string, + * AUTHOR_ID?: string, + * LAST_UPDATED?: string, + * EDITOR_ID?: string, + * SETTINGS?: string, + * ORIGIN_ID?: string, + * ORIGINATOR_ID?: string, + * RESULT_STATUS?: int, + * RESULT_STREAM?: int, + * RESULT_SOURCE_ID?: string, + * PROVIDER_PARAMS?: string, + * PROVIDER_DATA?: string, + * RESULT_MARK?: int, + * RESULT_VALUE?: string, + * RESULT_SUM?: string, + * RESULT_CURRENCY_ID?: string, + * AUTOCOMPLETE_RULE?: int, + * BINDINGS?: string, + * COMMUNICATIONS?: string, + * FILES?: string, + * WEBDAV_ELEMENTS?: string, + * } $filter + * + * @param array $select = ['ID','OWNER_ID','OWNER_TYPE_ID','TYPE_ID','PROVIDER_ID','PROVIDER_TYPE_ID','PROVIDER_GROUP_ID','ASSOCIATED_ENTITY_ID','SUBJECT','START_TIME','END_TIME','DEADLINE','COMPLETED','STATUS','RESPONSIBLE_ID','PRIORITY','NOTIFY_TYPE','NOTIFY_VALUE','DESCRIPTION','DESCRIPTION_TYPE','DIRECTION','LOCATION','CREATED','AUTHOR_ID','LAST_UPDATED','EDITOR_ID','SETTINGS','ORIGIN_ID','ORIGINATOR_ID','RESULT_STATUS','RESULT_STREAM','RESULT_SOURCE_ID','PROVIDER_PARAMS','PROVIDER_DATA','RESULT_MARK','RESULT_VALUE','RESULT_SUM','RESULT_CURRENCY_ID','AUTOCOMPLETE_RULE','BINDINGS','COMMUNICATIONS','FILES','WEBDAV_ELEMENTS','COMMUNICATIONS'] + * @param int $start + * + * @return ActivitiesResult + * @throws BaseException + * @throws TransportException + */ + public function list(array $order, array $filter, array $select, int $start): ActivitiesResult + { + return new ActivitiesResult( + $this->core->call( + 'crm.activity.list', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $start, + ] + ) + ); + } + + /** + * Updates the specified (existing) activity. + * + * @see https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_update.php + * + * @param int $itemId + * @param array{ + * ID?: int, + * OWNER_ID?: int, + * OWNER_TYPE_ID?: string, + * TYPE_ID?: string, + * PROVIDER_ID?: string, + * PROVIDER_TYPE_ID?: string, + * PROVIDER_GROUP_ID?: string, + * ASSOCIATED_ENTITY_ID?: int, + * SUBJECT?: string, + * START_TIME?: string, + * END_TIME?: string, + * DEADLINE?: string, + * COMPLETED?: string, + * STATUS?: string, + * RESPONSIBLE_ID?: string, + * PRIORITY?: string, + * NOTIFY_TYPE?: string, + * NOTIFY_VALUE?: int, + * DESCRIPTION?: string, + * DESCRIPTION_TYPE?: string, + * DIRECTION?: string, + * LOCATION?: string, + * CREATED?: string, + * AUTHOR_ID?: string, + * LAST_UPDATED?: string, + * EDITOR_ID?: string, + * SETTINGS?: string, + * ORIGIN_ID?: string, + * ORIGINATOR_ID?: string, + * RESULT_STATUS?: int, + * RESULT_STREAM?: int, + * RESULT_SOURCE_ID?: string, + * PROVIDER_PARAMS?: string, + * PROVIDER_DATA?: string, + * RESULT_MARK?: int, + * RESULT_VALUE?: string, + * RESULT_SUM?: string, + * RESULT_CURRENCY_ID?: string, + * AUTOCOMPLETE_RULE?: int, + * BINDINGS?: string, + * COMMUNICATIONS?: string, + * FILES?: string, + * WEBDAV_ELEMENTS?: string, + * } $fields + * + * @return UpdatedItemResult + * @throws BaseException + * @throws TransportException + */ + public function update(int $itemId, array $fields): UpdatedItemResult + { + return new UpdatedItemResult( + $this->core->call( + 'crm.activity.update', + [ + 'id' => $itemId, + 'fields' => $fields, + ] + ) + ); + } + + /** + * Count activity by filter + * + * @param array{ + * ID?: int, + * OWNER_ID?: int, + * OWNER_TYPE_ID?: string, + * TYPE_ID?: string, + * PROVIDER_ID?: string, + * PROVIDER_TYPE_ID?: string, + * PROVIDER_GROUP_ID?: string, + * ASSOCIATED_ENTITY_ID?: int, + * SUBJECT?: string, + * START_TIME?: string, + * END_TIME?: string, + * DEADLINE?: string, + * COMPLETED?: string, + * STATUS?: string, + * RESPONSIBLE_ID?: string, + * PRIORITY?: string, + * NOTIFY_TYPE?: string, + * NOTIFY_VALUE?: int, + * DESCRIPTION?: string, + * DESCRIPTION_TYPE?: string, + * DIRECTION?: string, + * LOCATION?: string, + * CREATED?: string, + * AUTHOR_ID?: string, + * LAST_UPDATED?: string, + * EDITOR_ID?: string, + * SETTINGS?: string, + * ORIGIN_ID?: string, + * ORIGINATOR_ID?: string, + * RESULT_STATUS?: int, + * RESULT_STREAM?: int, + * RESULT_SOURCE_ID?: string, + * PROVIDER_PARAMS?: string, + * PROVIDER_DATA?: string, + * RESULT_MARK?: int, + * RESULT_VALUE?: string, + * RESULT_SUM?: string, + * RESULT_CURRENCY_ID?: string, + * AUTOCOMPLETE_RULE?: int, + * BINDINGS?: string, + * COMMUNICATIONS?: string, + * FILES?: string, + * WEBDAV_ELEMENTS?: string, + * } $filter + * + * @return int + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function countByFilter(array $filter = []): int + { + return $this->list([], $filter, ['ID'], 1)->getCoreResponse()->getResponseData()->getPagination()->getTotal(); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/Service/Batch.php b/src/Services/CRM/Activity/Service/Batch.php new file mode 100644 index 00000000..d176a977 --- /dev/null +++ b/src/Services/CRM/Activity/Service/Batch.php @@ -0,0 +1,216 @@ +|ActivityItemResult[] + * @throws BaseException + */ + public function list(array $order, array $filter, array $select, ?int $limit = null): Generator + { + $this->log->debug( + 'list', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'limit' => $limit, + ] + ); + foreach ($this->batch->getTraversableList('crm.activity.list', $order, $filter, $select, $limit) as $key => $value) { + yield $key => new ActivityItemResult($value); + } + } + + /** + * Batch adding activity items + * + * @param array $activities + * + * @return \Generator + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function add(array $activities): Generator + { + $items = []; + foreach ($activities as $activity) { + $items[] = [ + 'fields' => $activity, + ]; + } + foreach ($this->batch->addEntityItems('crm.activity.add', $items) as $key => $item) { + yield $key => new AddedItemBatchResult($item); + } + } + + /** + * Batch delete activity items + * + * @param int[] $itemId + * + * @return \Generator|\Bitrix24\SDK\Core\Contracts\DeletedItemResultInterface[] + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function delete(array $itemId): Generator + { + foreach ($this->batch->deleteEntityItems('crm.activity.delete', $itemId) as $key => $item) { + yield $key => new DeletedItemBatchResult($item); + } + } +} \ No newline at end of file diff --git a/src/Services/CRM/CRMServiceBuilder.php b/src/Services/CRM/CRMServiceBuilder.php index 82b5040e..afe9d8e2 100644 --- a/src/Services/CRM/CRMServiceBuilder.php +++ b/src/Services/CRM/CRMServiceBuilder.php @@ -170,4 +170,20 @@ public function userfield(): Userfield\Service\Userfield return $this->serviceCache[__METHOD__]; } + + /** + * @return Activity\Service\Activity + */ + public function activity(): Activity\Service\Activity + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Activity\Service\Activity( + new Activity\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } } \ No newline at end of file diff --git a/src/Services/CRM/Contact/Service/Batch.php b/src/Services/CRM/Contact/Service/Batch.php index 55172488..696720a2 100644 --- a/src/Services/CRM/Contact/Service/Batch.php +++ b/src/Services/CRM/Contact/Service/Batch.php @@ -6,6 +6,7 @@ use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Result\AddedItemBatchResult; +use Bitrix24\SDK\Core\Result\DeletedItemBatchResult; use Bitrix24\SDK\Services\AbstractBatchService; use Bitrix24\SDK\Services\CRM\Contact\Result\ContactItemResult; use Generator; @@ -119,8 +120,8 @@ class Batch extends AbstractBatchService * WEB?: string, * IM?: string, * } $filter - * @param array $select = ['ID','HONORIFIC','NAME','SECOND_NAME','LAST_NAME','PHOTO','BIRTHDATE','TYPE_ID','SOURCE_ID','SOURCE_DESCRIPTION','POST','ADDRESS','ADDRESS_2','ADDRESS_CITY','ADDRESS_POSTAL_CODE','ADDRESS_REGION','ADDRESS_PROVINCE','ADDRESS_COUNTRY','ADDRESS_COUNTRY_CODE','ADDRESS_LOC_ADDR_ID','COMMENTS','OPENED','EXPORT','HAS_PHONE','HAS_EMAIL','HAS_IMOL','ASSIGNED_BY_ID','CREATED_BY_ID','MODIFY_BY_ID','DATE_CREATE','DATE_MODIFY','COMPANY_ID','COMPANY_IDS','LEAD_ID','ORIGINATOR_ID','ORIGIN_ID','ORIGIN_VERSION','FACE_ID','UTM_SOURCE','UTM_MEDIUM','UTM_CAMPAIGN','UTM_CONTENT','UTM_TERM','PHONE','EMAIL','WEB','IM'] - * @param int|null $limit + * @param array $select = ['ID','HONORIFIC','NAME','SECOND_NAME','LAST_NAME','PHOTO','BIRTHDATE','TYPE_ID','SOURCE_ID','SOURCE_DESCRIPTION','POST','ADDRESS','ADDRESS_2','ADDRESS_CITY','ADDRESS_POSTAL_CODE','ADDRESS_REGION','ADDRESS_PROVINCE','ADDRESS_COUNTRY','ADDRESS_COUNTRY_CODE','ADDRESS_LOC_ADDR_ID','COMMENTS','OPENED','EXPORT','HAS_PHONE','HAS_EMAIL','HAS_IMOL','ASSIGNED_BY_ID','CREATED_BY_ID','MODIFY_BY_ID','DATE_CREATE','DATE_MODIFY','COMPANY_ID','COMPANY_IDS','LEAD_ID','ORIGINATOR_ID','ORIGIN_ID','ORIGIN_VERSION','FACE_ID','UTM_SOURCE','UTM_MEDIUM','UTM_CAMPAIGN','UTM_CONTENT','UTM_TERM','PHONE','EMAIL','WEB','IM'] + * @param int|null $limit * * @return Generator * @throws BaseException @@ -130,10 +131,10 @@ public function list(array $order, array $filter, array $select, ?int $limit = n $this->log->debug( 'list', [ - 'order' => $order, + 'order' => $order, 'filter' => $filter, 'select' => $select, - 'limit' => $limit, + 'limit' => $limit, ] ); foreach ($this->batch->getTraversableList('crm.contact.list', $order, $filter, $select, $limit) as $key => $value) { @@ -208,4 +209,19 @@ public function add(array $contacts): Generator yield $key => new AddedItemBatchResult($item); } } + + /** + * Batch delete contact items + * + * @param int[] $contactId + * + * @return \Generator + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function delete(array $contactId): Generator + { + foreach ($this->batch->deleteEntityItems('crm.contact.delete', $contactId) as $key => $item) { + yield $key => new DeletedItemBatchResult($item); + } + } } \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Activity/Service/ActivityTest.php b/tests/Integration/Services/CRM/Activity/Service/ActivityTest.php new file mode 100644 index 00000000..f0b0acfc --- /dev/null +++ b/tests/Integration/Services/CRM/Activity/Service/ActivityTest.php @@ -0,0 +1,267 @@ +contactService->add(['NAME' => 'test contact'])->getId(); + $this->contactId[] = $contactId; + $this->activityId[] = $this->activityService->add( + [ + 'OWNER_ID' => $contactId, + 'OWNER_TYPE_ID' => 3, + 'TYPE_ID' => 2, + 'PROVIDER_ID' => 'VOXIMPLANT_CALL', + 'PROVIDER_TYPE_ID' => 'CALL', + 'SUBJECT' => 'test activity', + 'DESCRIPTION' => 'test activity description', + 'DESCRIPTION_TYPE' => '1', + 'DIRECTION' => '2', + 'COMMUNICATIONS' => [ + 0 => [ + 'TYPE' => 'PHONE', + 'VALUE' => '+79780194444', + ], + ], + ] + )->getId(); + // successfully add activity + $this->assertTrue(true); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers \Bitrix24\SDK\Services\CRM\Activity\Service\Activity::delete + */ + public function testDelete(): void + { + $contactId = $this->contactService->add(['NAME' => 'test contact'])->getId(); + $this->contactId[] = $contactId; + $activityId = $this->activityService->add( + [ + 'OWNER_ID' => $contactId, + 'OWNER_TYPE_ID' => 3, + 'TYPE_ID' => 2, + 'PROVIDER_ID' => 'VOXIMPLANT_CALL', + 'PROVIDER_TYPE_ID' => 'CALL', + 'SUBJECT' => 'test activity', + 'DESCRIPTION' => 'test activity description', + 'DESCRIPTION_TYPE' => '1', + 'DIRECTION' => '2', + 'COMMUNICATIONS' => [ + 0 => [ + 'TYPE' => 'PHONE', + 'VALUE' => '+79780194444', + ], + ], + ] + )->getId(); + $this->assertTrue($this->activityService->delete($activityId)->isSuccess()); + } + + /** + * @covers Contact::fields + * @throws BaseException + * @throws TransportException + */ + public function testFields(): void + { + self::assertIsArray($this->activityService->fields()->getFieldsDescription()); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers \Bitrix24\SDK\Services\CRM\Activity\Service\Activity::get + */ + public function testGet(): void + { + $contactId = $this->contactService->add(['NAME' => 'test contact'])->getId(); + $this->contactId[] = $contactId; + + $newActivity = [ + 'OWNER_ID' => $contactId, + 'OWNER_TYPE_ID' => 3, + 'TYPE_ID' => 2, + 'PROVIDER_ID' => 'VOXIMPLANT_CALL', + 'PROVIDER_TYPE_ID' => 'CALL', + 'SUBJECT' => 'test activity', + 'DESCRIPTION' => 'test activity description', + 'DESCRIPTION_TYPE' => '1', + 'DIRECTION' => '2', + 'COMMUNICATIONS' => [ + 0 => [ + 'TYPE' => 'PHONE', + 'VALUE' => '+79780194444', + ], + ], + ]; + $activityId = $this->activityService->add($newActivity)->getId(); + $this->activityId[] = $activityId; + + $activity = $this->activityService->get($activityId)->activity(); + + $this->assertEquals($newActivity['OWNER_ID'], $activity->OWNER_ID); + $this->assertEquals($newActivity['SUBJECT'], $activity->SUBJECT); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers \Bitrix24\SDK\Services\CRM\Activity\Service\Activity::list + */ + public function testList(): void + { + $contactId = $this->contactService->add(['NAME' => 'test contact'])->getId(); + $this->contactId[] = $contactId; + + $newActivity = []; + for ($i = 1; $i < 10; $i++) { + $newActivity[$i] = [ + 'OWNER_ID' => $contactId, + 'OWNER_TYPE_ID' => 3, + 'TYPE_ID' => 2, + 'PROVIDER_ID' => 'VOXIMPLANT_CALL', + 'PROVIDER_TYPE_ID' => 'CALL', + 'SUBJECT' => sprintf('test activity - %s', $i), + 'DESCRIPTION' => 'test activity description', + 'DESCRIPTION_TYPE' => '1', + 'DIRECTION' => '2', + 'COMMUNICATIONS' => [ + 0 => [ + 'TYPE' => 'PHONE', + 'VALUE' => '+79780194444', + ], + ], + ]; + $this->activityId[] = $this->activityService->add($newActivity[$i])->getId();; + } + + $res = $this->activityService->list( + ['ID' => 'DESC'], + [ + 'OWNER_ID' => $contactId, + ], + ["*", "COMMUNICATIONS"], + 0 + ); + $this->assertEquals(count($newActivity), count($res->getActivities())); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers \Bitrix24\SDK\Services\CRM\Activity\Service\Activity::update + */ + public function testUpdate(): void + { + $contactId = $this->contactService->add(['NAME' => 'test contact'])->getId(); + $this->contactId[] = $contactId; + + $newActivity = [ + 'OWNER_ID' => $contactId, + 'OWNER_TYPE_ID' => 3, + 'TYPE_ID' => 2, + 'PROVIDER_ID' => 'VOXIMPLANT_CALL', + 'PROVIDER_TYPE_ID' => 'CALL', + 'SUBJECT' => 'test activity', + 'DESCRIPTION' => 'test activity description', + 'DESCRIPTION_TYPE' => '1', + 'DIRECTION' => '2', + 'COMMUNICATIONS' => [ + 0 => [ + 'TYPE' => 'PHONE', + 'VALUE' => '+79780194444', + ], + ], + ]; + $activityId = $this->activityService->add($newActivity)->getId(); + $this->activityId[] = $activityId; + + $subject = 'qqqqq'; + $this->activityService->update($activityId, [ + 'SUBJECT' => $subject, + ]); + + $this->assertEquals($subject, $this->activityService->get($activityId)->activity()->SUBJECT); + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function testCountByFilter(): void + { + $contactId = $this->contactService->add(['NAME' => 'test contact'])->getId(); + $this->contactId[] = $contactId; + + $newActivity = []; + for ($i = 1; $i < 10; $i++) { + $newActivity[$i] = [ + 'OWNER_ID' => $contactId, + 'OWNER_TYPE_ID' => 3, + 'TYPE_ID' => 2, + 'PROVIDER_ID' => 'VOXIMPLANT_CALL', + 'PROVIDER_TYPE_ID' => 'CALL', + 'SUBJECT' => sprintf('test activity - %s', $i), + 'DESCRIPTION' => 'test activity description', + 'DESCRIPTION_TYPE' => '1', + 'DIRECTION' => '2', + 'COMMUNICATIONS' => [ + 0 => [ + 'TYPE' => 'PHONE', + 'VALUE' => '+79780194444', + ], + ], + ]; + $this->activityId[] = $this->activityService->add($newActivity[$i])->getId();; + } + + $this->assertEquals( + count($newActivity), + $this->activityService->countByFilter( + [ + 'OWNER_ID' => $contactId, + ] + ) + ); + } + + public function tearDown(): void + { + foreach ($this->activityService->batch->delete($this->activityId) as $result) { + } + foreach ($this->contactService->batch->delete($this->contactId) as $result) { + } + } + + public function setUp(): void + { + $this->activityService = Fabric::getServiceBuilder()->getCRMScope()->activity(); + $this->contactService = Fabric::getServiceBuilder()->getCRMScope()->contact(); + $this->contactId = []; + $this->activityId = []; + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Activity/Service/BatchTest.php b/tests/Integration/Services/CRM/Activity/Service/BatchTest.php new file mode 100644 index 00000000..f848cb7e --- /dev/null +++ b/tests/Integration/Services/CRM/Activity/Service/BatchTest.php @@ -0,0 +1,189 @@ +contactService->add(['NAME' => 'test contact'])->getId(); + $this->contactId[] = $contactId; + + $items = []; + for ($i = 1; $i < self::BATCH_TEST_ELEMENTS_COUNT; $i++) { + $items[] = [ + 'OWNER_ID' => $contactId, + 'OWNER_TYPE_ID' => 3, + 'TYPE_ID' => 2, + 'PROVIDER_ID' => 'VOXIMPLANT_CALL', + 'PROVIDER_TYPE_ID' => 'CALL', + 'SUBJECT' => 'test activity', + 'DESCRIPTION' => 'test activity description', + 'DESCRIPTION_TYPE' => '1', + 'DIRECTION' => '2', + 'COMMUNICATIONS' => [ + 0 => [ + 'TYPE' => 'PHONE', + 'VALUE' => '+79780194444', + ], + ], + ]; + } + + $cnt = 0; + $activityId = []; + foreach ($this->activityService->batch->add($items) as $item) { + $cnt++; + $activityId[] = $item->getId(); + } + self::assertEquals(count($items), $cnt); + + $cnt = 0; + foreach ($this->activityService->batch->delete($activityId) as $cnt => $deleteResult) { + $cnt++; + } + self::assertEquals(count($items), $cnt); + } + + /** + * @testdox Batch delete activities + * @covers \Bitrix24\SDK\Services\CRM\Activity\Service\Batch::delete() + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function testBatchDelete(): void + { + $contactId = $this->contactService->add(['NAME' => 'test contact'])->getId(); + $this->contactId[] = $contactId; + + $items = []; + for ($i = 1; $i < self::BATCH_TEST_ELEMENTS_COUNT; $i++) { + $items[] = [ + 'OWNER_ID' => $contactId, + 'OWNER_TYPE_ID' => 3, + 'TYPE_ID' => 2, + 'PROVIDER_ID' => 'VOXIMPLANT_CALL', + 'PROVIDER_TYPE_ID' => 'CALL', + 'SUBJECT' => 'test activity', + 'DESCRIPTION' => 'test activity description', + 'DESCRIPTION_TYPE' => '1', + 'DIRECTION' => '2', + 'COMMUNICATIONS' => [ + 0 => [ + 'TYPE' => 'PHONE', + 'VALUE' => '+79780194444', + ], + ], + ]; + } + + $cnt = 0; + $activityId = []; + foreach ($this->activityService->batch->add($items) as $item) { + $cnt++; + $activityId[] = $item->getId(); + } + self::assertEquals(count($items), $cnt); + + $cnt = 0; + foreach ($this->activityService->batch->delete($activityId) as $cnt => $deleteResult) { + $cnt++; + } + self::assertEquals(count($items), $cnt); + + + $this->assertEquals( + 0, + $this->activityService->countByFilter( + [ + 'OWNER_ID' => $contactId, + ] + ) + ); + } + + /** + * @testdox Batch list deals + * @covers \Bitrix24\SDK\Services\CRM\Contact\Service\Batch::list() + * @throws BaseException + * @throws TransportException + */ + public function testBatchList(): void + { + $contactId = $this->contactService->add(['NAME' => 'test contact'])->getId(); + $this->contactId[] = $contactId; + + $items = []; + for ($i = 1; $i < self::BATCH_TEST_ELEMENTS_COUNT; $i++) { + $items[] = [ + 'OWNER_ID' => $contactId, + 'OWNER_TYPE_ID' => 3, + 'TYPE_ID' => 2, + 'PROVIDER_ID' => 'VOXIMPLANT_CALL', + 'PROVIDER_TYPE_ID' => 'CALL', + 'SUBJECT' => 'test activity', + 'DESCRIPTION' => 'test activity description', + 'DESCRIPTION_TYPE' => '1', + 'DIRECTION' => '2', + 'COMMUNICATIONS' => [ + 0 => [ + 'TYPE' => 'PHONE', + 'VALUE' => '+79780194444', + ], + ], + ]; + } + + $cnt = 0; + $activityId = []; + foreach ($this->activityService->batch->add($items) as $item) { + $cnt++; + $activityId[] = $item->getId(); + } + + //fetch items + $itemsCnt = 0; + foreach ($this->activityService->batch->list(['ID' => 'DESC'], ['OWNER_ID' => $contactId], ['*']) as $item) { + $itemsCnt++; + } + $this->assertEquals( + count($activityId), + $itemsCnt, + sprintf( + 'batch activity list not fetched, expected %s, actual %s', + count($activityId), + $itemsCnt + ) + ); + } + + public function tearDown(): void + { + $this->contactService->batch->delete($this->contactId); + } + + public function setUp(): void + { + $this->activityService = Fabric::getServiceBuilder()->getCRMScope()->activity(); + $this->contactService = Fabric::getServiceBuilder()->getCRMScope()->contact(); + $this->contactId = []; + } +} \ No newline at end of file From f601c75ed4c8e30eb2cf71f0999a71b23201b46f Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 7 May 2022 01:32:31 +0300 Subject: [PATCH 321/647] remove examples Signed-off-by: mesilov --- .../core/batch-query-iterable-read-examp.php | 73 ----------------- .../core/batch-query-iterable-write-examp.php | 81 ------------------- examples/core/composer.json | 8 -- examples/core/core-examp.php | 26 ------ examples/core/oauth-examp.php | 61 -------------- examples/services/service-examp.php | 41 ---------- 6 files changed, 290 deletions(-) delete mode 100644 examples/core/batch-query-iterable-read-examp.php delete mode 100644 examples/core/batch-query-iterable-write-examp.php delete mode 100644 examples/core/composer.json delete mode 100644 examples/core/core-examp.php delete mode 100644 examples/core/oauth-examp.php delete mode 100644 examples/services/service-examp.php diff --git a/examples/core/batch-query-iterable-read-examp.php b/examples/core/batch-query-iterable-read-examp.php deleted file mode 100644 index 147a4b0b..00000000 --- a/examples/core/batch-query-iterable-read-examp.php +++ /dev/null @@ -1,73 +0,0 @@ -pushHandler(new StreamHandler('examples/logs/b24-api-client.log', Logger::DEBUG)); -$log->pushProcessor(new \Monolog\Processor\MemoryUsageProcessor(true, true)); -$log->pushProcessor(new \Monolog\Processor\IntrospectionProcessor()); -$log->debug('=============================================================='); - -try { - print('получаем данные:' . PHP_EOL); - - $core = (new \Bitrix24\SDK\Core\CoreBuilder()) - ->withLogger($log) - // INSERT YOUR WEBHOOK HERE - ->withWebhookUrl('https://') - // INSERT YOUR WEBHOOK HERE - ->build(); - $dealsService = new \Bitrix24\SDK\Services\CRM\Deals\Service\Deals($core, $log); - - $select = ['ID', 'TITLE']; - $firstResult = $dealsService->list([], ['>ID' => 50], $select); - $totalCount = $firstResult->getResponseData()->getPagination()->getTotal(); - - - // примеры формирования батч-запросов на чтение - // задача: прочитать все сделки из Б24 - // простая стратегия (с подсчётом количества элементов на стороне Б24 на каждом шаге): - - - $order = ['ID' => 'ASC']; - $filter = ['>ID' => 1]; - $select = ['ID', 'NAME', 'PHONE', 'EMAIL', 'IM']; - - $timeStart = microtime(true); - $elementsFromBatchCount = 0; - $batch = new \Bitrix24\SDK\Core\Batch($core, $log); - foreach ($batch->getTraversableList('crm.contact.list', $order, $filter, $select, 6000) as $queryItem) { - $curTime = microtime(true); - $elementsFromBatchCount++; - print(sprintf( - '%s Mb| %s sec |item %s |%s - %s ', - round(memory_get_peak_usage(true) / 1024 / 1024, 2), - round($curTime - $timeStart, 2), - $elementsFromBatchCount, - $queryItem['ID'], - $queryItem['NAME'] - ) . PHP_EOL); - } - - $timeEnd = microtime(true); - print(sprintf('batch query duration: %s seconds', round($timeEnd - $timeStart, 2)) . PHP_EOL . PHP_EOL); - print(sprintf('elements in bitrix24 count: %s', $totalCount) . PHP_EOL); - print(sprintf('elements from batch count: %s ', $elementsFromBatchCount) . PHP_EOL . PHP_EOL); -} catch (\Throwable $exception) { - print(sprintf('ошибка: %s', $exception->getMessage()) . PHP_EOL); - print(sprintf('тип: %s', get_class($exception)) . PHP_EOL); - print(sprintf('trace: %s', $exception->getTraceAsString()) . PHP_EOL); -} - - - - - - - - - diff --git a/examples/core/batch-query-iterable-write-examp.php b/examples/core/batch-query-iterable-write-examp.php deleted file mode 100644 index 8ffdbd20..00000000 --- a/examples/core/batch-query-iterable-write-examp.php +++ /dev/null @@ -1,81 +0,0 @@ -pushHandler(new StreamHandler('examples/logs/b24-api-client.log', Logger::DEBUG)); -$log->pushProcessor(new \Monolog\Processor\MemoryUsageProcessor(true, true)); - -try { - $core = (new \Bitrix24\SDK\Core\CoreBuilder()) - ->withLogger($log) - // INSERT YOUR WEBHOOK HERE - ->withWebhookUrl('https://') - // INSERT YOUR WEBHOOK HERE - ->build(); - - $arraySize = 100; - print(sprintf('Prepare raw data example...') . PHP_EOL); - $rawDeals = []; - for ($i = 0; $i < $arraySize; $i++) { - $rawDeals[] = [ - 'TITLE' => sprintf('deal-%s', $i), - 'OPPORTUNITY' => 500, - 'CONTACT_ID' => 76, - ]; - } - print(sprintf('deals data count: %s', count($rawDeals)) . PHP_EOL); - print(sprintf('--------') . PHP_EOL); - - - // собираем операции добавления сделок в батч-запросы - $batch = new \Bitrix24\SDK\Core\Batch($core, $log); - foreach ($rawDeals as $cnt => $deal) { - $batch->addCommand('crm.deal.add', $deal); - } - print(sprintf('batch commands registered') . PHP_EOL); - - - // получаем данные батч-запросов - print(sprintf('call batch queries and get traversable results for each command...') . PHP_EOL); - - - // iterate api-calls result - $timeStart = microtime(true); - foreach ($batch->getTraversable(true) as $queryCnt => $queryResultData) { - /** - * @var $queryResultData \Bitrix24\SDK\Core\Response\DTO\ResponseData - */ - - print(sprintf(' single query number %s: ', $queryCnt) . PHP_EOL); - print(sprintf( - ' time |start: %s |duration %s |', - $queryResultData->getTime()->getDateStart()->format('H:i:s'), - $queryResultData->getTime()->getDuration(), - ) . PHP_EOL); - - print(sprintf(' deal id: %s', $queryResultData->getResult()->getResultData()[0]) . PHP_EOL); - - print(sprintf(' --') . PHP_EOL); - } - $timeEnd = microtime(true); - print(sprintf('batch query duration: %s seconds', round($timeEnd - $timeStart, 2)) . PHP_EOL . PHP_EOL); -} catch (\Throwable $exception) { - print(sprintf('ошибка: %s', $exception->getMessage()) . PHP_EOL); - print(sprintf('тип: %s', get_class($exception)) . PHP_EOL); - print(sprintf('trace: %s', $exception->getTraceAsString()) . PHP_EOL); -} - - - - - - - - - - diff --git a/examples/core/composer.json b/examples/core/composer.json deleted file mode 100644 index ceb68f23..00000000 --- a/examples/core/composer.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "require": { - "monolog/monolog": "2.*" - }, - "require-dev": { - "roave/security-advisories": "dev-master" - } -} \ No newline at end of file diff --git a/examples/core/core-examp.php b/examples/core/core-examp.php deleted file mode 100644 index e4d01a0e..00000000 --- a/examples/core/core-examp.php +++ /dev/null @@ -1,26 +0,0 @@ -pushHandler(new StreamHandler('b24-api-client-debug.log', Logger::DEBUG)); - -$client = HttpClient::create(); - -$credentials = new \Bitrix24\SDK\Core\Credentials\Credentials( - new \Bitrix24\SDK\Core\Credentials\WebhookUrl('b24 domain'), - null, - null -); - -$apiClient = new \Bitrix24\SDK\Core\ApiClient($credentials, $client, $log); - -$result = $apiClient->getResponse('crm.deal.get', ['id' => 5]); - -var_dump($result->getContent()); diff --git a/examples/core/oauth-examp.php b/examples/core/oauth-examp.php deleted file mode 100644 index 1e9badd6..00000000 --- a/examples/core/oauth-examp.php +++ /dev/null @@ -1,61 +0,0 @@ -pushHandler(new StreamHandler('b24-api-client-debug.log', Logger::DEBUG)); - -$client = HttpClient::create(['http_version' => '2.0']); -$traceableClient = new \Symfony\Component\HttpClient\TraceableHttpClient($client); -$traceableClient->setLogger($log); - -$appProfile = new \Bitrix24\SDK\Core\Credentials\ApplicationProfile( - 'local.5f9d4c50b2bf08.70341243', - 'YE56q7neK8SJgP8xqDBlTP2oPYSUf7HUySkob0w9wOWFr1XZCv', - new \Bitrix24\SDK\Core\Credentials\Scope( - [ - 'crm', - ] - ) -); -$token = new \Bitrix24\SDK\Core\Credentials\AccessToken( - '50cc… access token', - '404b… refresh token', - 0 -); -$domain = 'https://domain.bitrix24.ru'; -$credentials = \Bitrix24\SDK\Core\Credentials\Credentials::createForOAuth($token, $appProfile, $domain); - -try { - $apiClient = new \Bitrix24\SDK\Core\ApiClient($credentials, $traceableClient, $log); - - $ed = new \Symfony\Component\EventDispatcher\EventDispatcher(); - $ed->addListener( - \Bitrix24\SDK\Events\AuthTokenRenewedEvent::class, - static function (\Bitrix24\SDK\Events\AuthTokenRenewedEvent $event) { - var_dump('AuthTokenRenewed!'); - print($event->getRenewedToken()->getAccessToken()->getAccessToken() . PHP_EOL); - } - ); - - $app = (new \Bitrix24\SDK\Core\CoreBuilder())->withCredentials($credentials)->withApiClient($apiClient)->build(); - - $log->debug('================================'); - - // api call with expired access token - $res = $app->call('app.info'); - print('result:' . PHP_EOL); - - var_dump($res->getResponseData()->getResult()->getResultData()); - var_dump($res->getResponseData()->getTime()->getDuration()); -} catch (\Throwable $exception) { - print(sprintf('error: %s', $exception->getMessage()) . PHP_EOL); - print(sprintf('class: %s', get_class($exception)) . PHP_EOL); - print(sprintf('trace: %s', $exception->getTraceAsString()) . PHP_EOL); -} \ No newline at end of file diff --git a/examples/services/service-examp.php b/examples/services/service-examp.php deleted file mode 100644 index f048618b..00000000 --- a/examples/services/service-examp.php +++ /dev/null @@ -1,41 +0,0 @@ -pushHandler(new StreamHandler('examples/logs/b24-api-client.log', Logger::DEBUG)); -$log->pushProcessor(new \Monolog\Processor\MemoryUsageProcessor(true, true)); -$log->pushProcessor(new \Monolog\Processor\IntrospectionProcessor()); -$log->debug('=============================================================='); - -try { - print('получаем данные:' . PHP_EOL); - - // сконфигурировали SDK - $core = (new \Bitrix24\SDK\Core\CoreBuilder()) - ->withLogger($log) - // INSERT YOUR WEBHOOK HERE - ->withWebhookUrl('') - // INSERT YOUR WEBHOOK HERE - ->build(); - $batch = new \Bitrix24\SDK\Core\Batch($core, $log); - $serviceBuilder = new ServiceBuilder($core, $batch, $log); - - // получили сервис по работе с контактами из модуля CRM - // именно сервис предоставляет CRUD+ api по работе с сущностью - $contactService = $serviceBuilder->getCRMScope()->contacts(); - - // получили первые 50 контактов вызвав метод crm.contact.list - $contacts = $contactService->list([], [], [], 0); - var_dump($contacts->getResponseData()->getResult()->getResultData()); - var_dump($contacts->getResponseData()->getPagination()->getTotal()); -} catch (\Throwable $exception) { - print(sprintf('ошибка: %s', $exception->getMessage()) . PHP_EOL); - print(sprintf('тип: %s', get_class($exception)) . PHP_EOL); - print(sprintf('trace: %s', $exception->getTraceAsString()) . PHP_EOL); -} \ No newline at end of file From 0df5ec461c3c76db4b9436148cff16bccb4941a1 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 9 May 2022 21:48:04 +0300 Subject: [PATCH 322/647] fix phpstan check Signed-off-by: mesilov --- src/Core/Contracts/BatchInterface.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Core/Contracts/BatchInterface.php b/src/Core/Contracts/BatchInterface.php index d259a9d2..fd676b4d 100644 --- a/src/Core/Contracts/BatchInterface.php +++ b/src/Core/Contracts/BatchInterface.php @@ -18,11 +18,11 @@ interface BatchInterface /** * Batch wrapper for *.list methods without counting elements on every api-call * - * @param string $apiMethod - * @param array $order - * @param array $filter - * @param array $select - * @param int|null $limit + * @param string $apiMethod + * @param array $order + * @param array $filter + * @param array $select + * @param int|null $limit * * @return Generator * @throws BaseException From 10c30087660c03b58371641b3fe6a46249d411c5 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 9 May 2022 21:56:20 +0300 Subject: [PATCH 323/647] add user consent scope Signed-off-by: mesilov --- src/Services/ServiceBuilder.php | 13 +++++ .../Result/UserConsentAgreementItemResult.php | 39 +++++++++++++ .../Result/UserConsentAgreementResult.php | 20 +++++++ .../UserConsentAgreementTextItemResult.php | 17 ++++++ .../Result/UserConsentAgreementTextResult.php | 20 +++++++ .../Result/UserConsentAgreementsResult.php | 26 +++++++++ .../UserConsent/Service/UserConsent.php | 27 +++++++++ .../Service/UserConsentAgreement.php | 47 +++++++++++++++ .../UserConsent/UserConsentServiceBuilder.php | 40 +++++++++++++ .../Service/UserConsentAgreementTest.php | 58 +++++++++++++++++++ .../UserConsent/Service/UserConsentTest.php | 52 +++++++++++++++++ 11 files changed, 359 insertions(+) create mode 100644 src/Services/UserConsent/Result/UserConsentAgreementItemResult.php create mode 100644 src/Services/UserConsent/Result/UserConsentAgreementResult.php create mode 100644 src/Services/UserConsent/Result/UserConsentAgreementTextItemResult.php create mode 100644 src/Services/UserConsent/Result/UserConsentAgreementTextResult.php create mode 100644 src/Services/UserConsent/Result/UserConsentAgreementsResult.php create mode 100644 src/Services/UserConsent/Service/UserConsent.php create mode 100644 src/Services/UserConsent/Service/UserConsentAgreement.php create mode 100644 src/Services/UserConsent/UserConsentServiceBuilder.php create mode 100644 tests/Integration/Services/UserConsent/Service/UserConsentAgreementTest.php create mode 100644 tests/Integration/Services/UserConsent/Service/UserConsentTest.php diff --git a/src/Services/ServiceBuilder.php b/src/Services/ServiceBuilder.php index fa8a51a9..f614d060 100644 --- a/src/Services/ServiceBuilder.php +++ b/src/Services/ServiceBuilder.php @@ -7,6 +7,7 @@ use Bitrix24\SDK\Services\CRM\CRMServiceBuilder; use Bitrix24\SDK\Services\IM\IMServiceBuilder; use Bitrix24\SDK\Services\Main\MainServiceBuilder; +use Bitrix24\SDK\Services\UserConsent\UserConsentServiceBuilder; /** * Class ServiceBuilder @@ -50,4 +51,16 @@ public function getMainScope(): MainServiceBuilder return $this->serviceCache[__METHOD__]; } + + /** + * @return \Bitrix24\SDK\Services\UserConsent\UserConsentServiceBuilder + */ + public function getUserConsentScope(): UserConsentServiceBuilder + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new UserConsentServiceBuilder($this->core, $this->batch, $this->bulkItemsReader, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } } \ No newline at end of file diff --git a/src/Services/UserConsent/Result/UserConsentAgreementItemResult.php b/src/Services/UserConsent/Result/UserConsentAgreementItemResult.php new file mode 100644 index 00000000..90147522 --- /dev/null +++ b/src/Services/UserConsent/Result/UserConsentAgreementItemResult.php @@ -0,0 +1,39 @@ +data[$offset] !== '' && $this->data[$offset] !== null) { + return (int)$this->data[$offset]; + } + + return null; + case 'ACTIVE': + return $this->data[$offset] === 'Y'; + default: + return $this->data[$offset] ?? null; + } + } +} \ No newline at end of file diff --git a/src/Services/UserConsent/Result/UserConsentAgreementResult.php b/src/Services/UserConsent/Result/UserConsentAgreementResult.php new file mode 100644 index 00000000..a361300c --- /dev/null +++ b/src/Services/UserConsent/Result/UserConsentAgreementResult.php @@ -0,0 +1,20 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData()); + } +} \ No newline at end of file diff --git a/src/Services/UserConsent/Result/UserConsentAgreementTextItemResult.php b/src/Services/UserConsent/Result/UserConsentAgreementTextItemResult.php new file mode 100644 index 00000000..099efd59 --- /dev/null +++ b/src/Services/UserConsent/Result/UserConsentAgreementTextItemResult.php @@ -0,0 +1,17 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData()); + } +} \ No newline at end of file diff --git a/src/Services/UserConsent/Result/UserConsentAgreementsResult.php b/src/Services/UserConsent/Result/UserConsentAgreementsResult.php new file mode 100644 index 00000000..2267cbad --- /dev/null +++ b/src/Services/UserConsent/Result/UserConsentAgreementsResult.php @@ -0,0 +1,26 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { + $res[] = new UserConsentAgreementItemResult($item); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/UserConsent/Service/UserConsent.php b/src/Services/UserConsent/Service/UserConsent.php new file mode 100644 index 00000000..05fc9896 --- /dev/null +++ b/src/Services/UserConsent/Service/UserConsent.php @@ -0,0 +1,27 @@ +core->call('userconsent.consent.add', $consentFields)); + } +} \ No newline at end of file diff --git a/src/Services/UserConsent/Service/UserConsentAgreement.php b/src/Services/UserConsent/Service/UserConsentAgreement.php new file mode 100644 index 00000000..d5418d19 --- /dev/null +++ b/src/Services/UserConsent/Service/UserConsentAgreement.php @@ -0,0 +1,47 @@ +core->call('userconsent.agreement.list')); + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function text(int $agreementId, array $replace): UserConsentAgreementTextResult + { + if (!array_key_exists('button_caption', $replace)) { + throw new InvalidArgumentException('field «button_caption» not found in argument replace '); + } + if (!array_key_exists('fields', $replace)) { + throw new InvalidArgumentException('field «fields» not found in argument replace'); + } + + return new UserConsentAgreementTextResult( + $this->core->call('userconsent.agreement.text', [ + 'id' => $agreementId, + 'replace' => $replace, + ]) + ); + } +} \ No newline at end of file diff --git a/src/Services/UserConsent/UserConsentServiceBuilder.php b/src/Services/UserConsent/UserConsentServiceBuilder.php new file mode 100644 index 00000000..509966d0 --- /dev/null +++ b/src/Services/UserConsent/UserConsentServiceBuilder.php @@ -0,0 +1,40 @@ +serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new UserConsentAgreement($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + /** + * get user consent service + * + * @return UserConsent + */ + public function UserConsent(): UserConsent + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new UserConsent($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } +} \ No newline at end of file diff --git a/tests/Integration/Services/UserConsent/Service/UserConsentAgreementTest.php b/tests/Integration/Services/UserConsent/Service/UserConsentAgreementTest.php new file mode 100644 index 00000000..3f694869 --- /dev/null +++ b/tests/Integration/Services/UserConsent/Service/UserConsentAgreementTest.php @@ -0,0 +1,58 @@ +assertIsArray($this->userConsentAgreementService->list()->getAgreements()); + } + + /** + * @covers UserConsentAgreement::text + * @testdox test get agreements list + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function testText(): void + { + // get agreement id + $agreements = $this->userConsentAgreementService->list()->getAgreements(); + // empty agreement list + if (count($agreements) === 0) { + $this->assertTrue(true); + + return; + } + $agreementId = $agreements[0]->ID; + $agreementText = $this->userConsentAgreementService->text($agreementId, [ + 'button_caption' => 'Button call to action title', + 'fields' => 'fields collection: email, phone', + ])->text(); + + $this->assertNotNull($agreementText->TEXT); + $this->assertNotNull($agreementText->LABEL); + } + + public function setUp(): void + { + $this->userConsentAgreementService = Fabric::getServiceBuilder()->getUserConsentScope()->UserConsentAgreement(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/UserConsent/Service/UserConsentTest.php b/tests/Integration/Services/UserConsent/Service/UserConsentTest.php new file mode 100644 index 00000000..7759a6a2 --- /dev/null +++ b/tests/Integration/Services/UserConsent/Service/UserConsentTest.php @@ -0,0 +1,52 @@ +userConsentAgreementService->list()->getAgreements(); + // empty agreement list + if (count($agreements) === 0) { + $this->assertTrue(true); + + return; + } + + $agreementId = $agreements[0]->ID; + $res = $this->userConsentService->add( + [ + 'agreement_id' => $agreementId, + 'ip' => '127.0.0.1', + 'origin_id' => 'offline', + 'originator_id' => 'test@gmail.com', + ] + ); + $this->assertIsInt($res->getId()); + } + + public function setUp(): void + { + $this->userConsentService = Fabric::getServiceBuilder()->getUserConsentScope()->UserConsent(); + $this->userConsentAgreementService = Fabric::getServiceBuilder()->getUserConsentScope()->UserConsentAgreement(); + } +} \ No newline at end of file From 7b0bf7defa37174df9411c2f09f2915a9b937716 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 9 May 2022 21:57:13 +0300 Subject: [PATCH 324/647] add user consent scope description Signed-off-by: mesilov --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c5ac0f0..ff4a2810 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ * add CRM Activity support [добавить поддержку дел](https://github.com/mesilov/bitrix24-php-sdk/issues/283) * add in scope «CRM» `Services\CRM\Contact\Service\Batch::delete` batch delete contacts +* add service for work with user consent agreement [добавить поддержку сущности «Соглашения»](https://github.com/mesilov/bitrix24-php-sdk/issues/285) +* add scope `UserConsent` ### Bugfix From 8b86b63007fb1d1d62b8dd2d434a6d27ebe23062 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 9 May 2022 21:57:33 +0300 Subject: [PATCH 325/647] add tests for main scope Signed-off-by: mesilov --- .../Services/Main/Service/MainTest.php | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 tests/Integration/Services/Main/Service/MainTest.php diff --git a/tests/Integration/Services/Main/Service/MainTest.php b/tests/Integration/Services/Main/Service/MainTest.php new file mode 100644 index 00000000..c13eb6c8 --- /dev/null +++ b/tests/Integration/Services/Main/Service/MainTest.php @@ -0,0 +1,31 @@ +assertIsArray($this->mainService->getAvailableMethods()->getResponseData()->getResult()->getResultData()); + } + + public function setUp(): void + { + $this->mainService = Fabric::getServiceBuilder()->getMainScope()->main(); + } +} \ No newline at end of file From 64ce299b613a94a7ea5b74aeb28f3e98487c7668 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 9 May 2022 22:06:13 +0300 Subject: [PATCH 326/647] add description Signed-off-by: mesilov --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff4a2810..2672b9a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ * add CRM Activity support [добавить поддержку дел](https://github.com/mesilov/bitrix24-php-sdk/issues/283) * add in scope «CRM» `Services\CRM\Contact\Service\Batch::delete` batch delete contacts * add service for work with user consent agreement [добавить поддержку сущности «Соглашения»](https://github.com/mesilov/bitrix24-php-sdk/issues/285) -* add scope `UserConsent` +* add scope `UserConsent` for ServiceBuilder ### Bugfix From 5afb3a2fc2b9e18553de2fc021334ab81f0fcce8 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 2 Jun 2022 17:24:33 +0300 Subject: [PATCH 327/647] bump symfony to 6.* Signed-off-by: mesilov --- CHANGELOG.md | 12 +++++++++++- composer.json | 14 +++++++------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aff9d94a..1a8e3f33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,16 @@ # bitrix24-php-sdk change log -## 2.0-alpha.6 — 7.02.2021 +## 2.0-alpha.7 — 7.06.2022 + +### Added + +* add `Placements` [add placements support](https://github.com/mesilov/bitrix24-php-sdk/issues/274) + +### Changed + +* bump `symfony/*` to `6.*` version requirement. + +## 2.0-alpha.6 — 7.02.2022 ### Added diff --git a/composer.json b/composer.json index 900ff842..5526a702 100644 --- a/composer.json +++ b/composer.json @@ -22,19 +22,19 @@ "ext-curl": "*", "psr/log": "^1.1.4 || ^2.0 || ^3.0", "fig/http-message-util": "1.1.*", - "symfony/http-client": "5.4.*", + "symfony/http-client": "5.4.* || 6.*", "symfony/http-client-contracts": "^2.5", - "symfony/event-dispatcher": "5.4.*", + "symfony/event-dispatcher": "5.4.* || 6.*", "ramsey/uuid": "^4.2.3" }, "require-dev": { "monolog/monolog": "2.1.*", - "symfony/console": "5.4.*", - "symfony/dotenv": "5.4.*", - "symfony/debug-bundle": "5.4.*", - "phpstan/phpstan": "1.1.*", + "symfony/console": "5.4.* || 6.*", + "symfony/dotenv": "5.4.* || 6.*", + "symfony/debug-bundle": "5.4.* || 6.*", + "phpstan/phpstan": "1.*", "phpunit/phpunit": "9.5.*", - "symfony/stopwatch": "5.4.*", + "symfony/stopwatch": "5.4.* || 6.*", "roave/security-advisories": "dev-master" }, "autoload": { From 5356ccbf0501394551d7616cea22c485a671f374 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 2 Jun 2022 17:37:50 +0300 Subject: [PATCH 328/647] bump symfony contracts to 3.* Signed-off-by: mesilov --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 5526a702..2a647ba1 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "psr/log": "^1.1.4 || ^2.0 || ^3.0", "fig/http-message-util": "1.1.*", "symfony/http-client": "5.4.* || 6.*", - "symfony/http-client-contracts": "^2.5", + "symfony/http-client-contracts": "^2.5 || ^3.*", "symfony/event-dispatcher": "5.4.* || 6.*", "ramsey/uuid": "^4.2.3" }, From f5242dec2452e58760819f99fd331e951044a4b0 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 2 Jun 2022 17:38:37 +0300 Subject: [PATCH 329/647] bump symfony contracts to 3.1 Signed-off-by: mesilov --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 2a647ba1..6bd0333b 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "psr/log": "^1.1.4 || ^2.0 || ^3.0", "fig/http-message-util": "1.1.*", "symfony/http-client": "5.4.* || 6.*", - "symfony/http-client-contracts": "^2.5 || ^3.*", + "symfony/http-client-contracts": "^2.5 || ^3.1", "symfony/event-dispatcher": "5.4.* || 6.*", "ramsey/uuid": "^4.2.3" }, From 5fea13ba1a7b3aac6683371fed2fb9fc3d5ce589 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 5 Jun 2022 11:55:54 +0300 Subject: [PATCH 330/647] fix credentials Signed-off-by: mesilov --- composer.json | 1 + src/Core/CoreBuilder.php | 3 +- src/Core/Credentials/Credentials.php | 16 +++-- src/Core/Credentials/Scope.php | 3 + .../Unit/Core/Credentials/CredentialsTest.php | 60 +++++++++++++++++++ 5 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 tests/Unit/Core/Credentials/CredentialsTest.php diff --git a/composer.json b/composer.json index 6bd0333b..0a09205e 100644 --- a/composer.json +++ b/composer.json @@ -24,6 +24,7 @@ "fig/http-message-util": "1.1.*", "symfony/http-client": "5.4.* || 6.*", "symfony/http-client-contracts": "^2.5 || ^3.1", + "symfony/http-foundation": "5.4.* || 6.*", "symfony/event-dispatcher": "5.4.* || 6.*", "ramsey/uuid": "^4.2.3" }, diff --git a/src/Core/CoreBuilder.php b/src/Core/CoreBuilder.php index d55e4109..1d2175a4 100644 --- a/src/Core/CoreBuilder.php +++ b/src/Core/CoreBuilder.php @@ -58,6 +58,7 @@ public function __construct() public function withCredentials(Credentials $credentials): self { $this->credentials = $credentials; + return $this; } @@ -118,7 +119,7 @@ public function build(): CoreInterface if ($this->webhookUrl !== null) { $this->credentials = Credentials::createForWebHook($this->webhookUrl); } elseif ($this->credentials === null) { - throw new InvalidArgumentException('you must set webhook url or oauth credentials'); + throw new InvalidArgumentException('you must set webhook url or oauth credentials before call method build'); } if ($this->apiClient === null) { diff --git a/src/Core/Credentials/Credentials.php b/src/Core/Credentials/Credentials.php index 8c8932d2..862e6764 100644 --- a/src/Core/Credentials/Credentials.php +++ b/src/Core/Credentials/Credentials.php @@ -4,6 +4,8 @@ namespace Bitrix24\SDK\Core\Credentials; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; + /** * Class Credentials * @@ -23,6 +25,8 @@ class Credentials * @param AccessToken|null $accessToken * @param ApplicationProfile|null $applicationProfile * @param string|null $domainUrl + * + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException */ public function __construct( ?WebhookUrl $webhookUrl, @@ -33,6 +37,10 @@ public function __construct( $this->webhookUrl = $webhookUrl; $this->accessToken = $accessToken; $this->applicationProfile = $applicationProfile; + + if (($domainUrl !== null) && filter_var($domainUrl, FILTER_VALIDATE_URL) === false) { + throw new InvalidArgumentException(sprintf('domain URL %s is invalid', $domainUrl)); + } $this->domainUrl = $domainUrl; if ($this->accessToken === null && $this->webhookUrl === null) { throw new \LogicException('you must set on of auth type: webhook or OAuth 2.0'); @@ -65,13 +73,11 @@ public function getDomainUrl(): string { if ($this->getWebhookUrl() !== null) { $arUrl = parse_url($this->getWebhookUrl()->getUrl()); - - $url = sprintf('%s://%s', $arUrl['scheme'], $arUrl['host']); } else { - $url = $this->domainUrl; + $arUrl = parse_url($this->domainUrl); } - return $url; + return sprintf('%s://%s', $arUrl['scheme'], $arUrl['host']); } /** @@ -94,6 +100,7 @@ public function getAccessToken(): ?AccessToken * @param WebhookUrl $webhookUrl * * @return self + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException */ public static function createForWebHook(WebhookUrl $webhookUrl): self { @@ -111,6 +118,7 @@ public static function createForWebHook(WebhookUrl $webhookUrl): self * @param string $domainUrl * * @return self + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException */ public static function createForOAuth(AccessToken $accessToken, ApplicationProfile $applicationProfile, string $domainUrl): self { diff --git a/src/Core/Credentials/Scope.php b/src/Core/Credentials/Scope.php index 3ddda1fa..4f1f0ba7 100644 --- a/src/Core/Credentials/Scope.php +++ b/src/Core/Credentials/Scope.php @@ -55,6 +55,9 @@ class Scope 'telephony', 'timeman', 'user', + 'user_basic', + 'user_brief', + 'user.userfield', 'userconsent', ]; diff --git a/tests/Unit/Core/Credentials/CredentialsTest.php b/tests/Unit/Core/Credentials/CredentialsTest.php new file mode 100644 index 00000000..748c3b43 --- /dev/null +++ b/tests/Unit/Core/Credentials/CredentialsTest.php @@ -0,0 +1,60 @@ +assertEquals($expectedDomainUrl, $credentials->getDomainUrl()); + } + + /** + * @return \Generator + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @throws \Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException + */ + public function credentialsDataProviderWithDomainUrlVariants(): Generator + { + yield 'with webhook walid domain url' => [ + Credentials::createForWebHook(new WebhookUrl('https://bitrix24-php-sdk-playground.bitrix24.ru/rest/1/valid-webhook/')), + 'https://bitrix24-php-sdk-playground.bitrix24.ru', + ]; + yield 'with oauth domain url with end /' => [ + Credentials::createForOAuth( + new AccessToken('', '', 0), + new ApplicationProfile('', '', new Scope(['crm'])), + 'https://bitrix24-php-sdk-playground.bitrix24.ru/' + ), + 'https://bitrix24-php-sdk-playground.bitrix24.ru', + ]; + yield 'with oauth domain url without end /' => [ + Credentials::createForOAuth( + new AccessToken('', '', 0), + new ApplicationProfile('', '', new Scope(['crm'])), + 'https://bitrix24-php-sdk-playground.bitrix24.ru' + ), + 'https://bitrix24-php-sdk-playground.bitrix24.ru', + ]; + } +} From c1e999596ef22cc143dd6a978c8f8262730f69e6 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 5 Jun 2022 23:35:04 +0300 Subject: [PATCH 331/647] fix AbstractItem.php Signed-off-by: mesilov --- CHANGELOG.md | 1 + src/Core/Result/AbstractItem.php | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a8e3f33..068fd930 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ ### Changed * bump `symfony/*` to `6.*` version requirement. +* fix type compatible errors for `Core\Result\AbstractItem` ## 2.0-alpha.6 — 7.02.2022 diff --git a/src/Core/Result/AbstractItem.php b/src/Core/Result/AbstractItem.php index ca18e485..a3e3e409 100644 --- a/src/Core/Result/AbstractItem.php +++ b/src/Core/Result/AbstractItem.php @@ -4,14 +4,17 @@ namespace Bitrix24\SDK\Core\Result; +use ArrayIterator; use Bitrix24\SDK\Core\Exceptions\ImmutableResultViolationException; +use IteratorAggregate; +use Traversable; /** * Class AbstractItem * * @package Bitrix24\SDK\Core\Result */ -abstract class AbstractItem implements \IteratorAggregate +abstract class AbstractItem implements IteratorAggregate { protected array $data; @@ -71,9 +74,9 @@ public function __unset($offset) /** * {@inheritdoc} */ - public function getIterator() + public function getIterator():Traversable { - return new \ArrayIterator($this->data); + return new ArrayIterator($this->data); } /** From ef954b000a9b9f50cddf50457a68c0c156ec4905 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 5 Jun 2022 23:46:37 +0300 Subject: [PATCH 332/647] add ApplicationStatus Signed-off-by: mesilov --- src/Application/ApplicationStatus.php | 119 ++++++++++++++++++ .../Application/ApplicationStatusTest.php | 70 +++++++++++ 2 files changed, 189 insertions(+) create mode 100644 src/Application/ApplicationStatus.php create mode 100644 tests/Unit/Application/ApplicationStatusTest.php diff --git a/src/Application/ApplicationStatus.php b/src/Application/ApplicationStatus.php new file mode 100644 index 00000000..54500ccf --- /dev/null +++ b/src/Application/ApplicationStatus.php @@ -0,0 +1,119 @@ +statusCode = 'free'; + break; + case self::STATUS_SHORT_DEMO: + $this->statusCode = 'demo'; + break; + case self::STATUS_SHORT_TRIAL: + $this->statusCode = 'trial'; + break; + case self::STATUS_SHORT_PAID: + $this->statusCode = 'paid'; + break; + case self::STATUS_SHORT_LOCAL: + $this->statusCode = 'local'; + break; + case self::STATUS_SHORT_SUBSCRIPTION: + $this->statusCode = 'subscription'; + break; + default: + throw new InvalidArgumentException( + sprintf('unknown application status code %s', $statusShortCode) + ); + } + } + + /** + * @return bool + */ + public function isFree(): bool + { + return 'free' === $this->statusCode; + } + + /** + * @return bool + */ + public function isDemo(): bool + { + return 'demo' === $this->statusCode; + } + + /** + * @return bool + */ + public function isTrial(): bool + { + return 'trial' === $this->statusCode; + } + + /** + * @return bool + */ + public function isPaid(): bool + { + return 'paid' === $this->statusCode; + } + + /** + * @return bool + */ + public function isLocal(): bool + { + return 'local' === $this->statusCode; + } + + /** + * @return bool + */ + public function isSubscription(): bool + { + return 'subscription' === $this->statusCode; + } + + /** + * @return string + */ + public function getStatusCode(): string + { + return $this->statusCode; + } + + /** + * @param \Symfony\Component\HttpFoundation\Request $request + * + * @return self + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public static function initFromRequest(Request $request): self + { + return new self($request->request->getAlpha('status')); + } +} \ No newline at end of file diff --git a/tests/Unit/Application/ApplicationStatusTest.php b/tests/Unit/Application/ApplicationStatusTest.php new file mode 100644 index 00000000..cdf70fb6 --- /dev/null +++ b/tests/Unit/Application/ApplicationStatusTest.php @@ -0,0 +1,70 @@ +assertEquals( + $longCode, + (new ApplicationStatus($shortCode))->getStatusCode() + ); + } + + /** + * @return void + */ + public function testInvalidStatusCode(): void + { + $this->expectException(InvalidArgumentException::class); + new ApplicationStatus('foo'); + } + + /** + * @return \Generator + */ + public function statusDataProvider(): Generator + { + yield 'free' => [ + 'F', + 'free', + ]; + + yield 'demo' => [ + 'D', + 'demo', + ]; + yield 'trial' => [ + 'T', + 'trial', + ]; + yield 'paid' => [ + 'P', + 'paid', + ]; + yield 'local' => [ + 'L', + 'local', + ]; + yield 'subscription' => [ + 'S', + 'subscription', + ]; + } +} \ No newline at end of file From c8b44e3e5620edfc275c8f13abe411aa9568723b Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 5 Jun 2022 23:51:10 +0300 Subject: [PATCH 333/647] add initFromPlacementRequest method Signed-off-by: mesilov --- CHANGELOG.md | 2 ++ src/Core/Credentials/AccessToken.php | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 068fd930..f4b1885f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ ### Added * add `Placements` [add placements support](https://github.com/mesilov/bitrix24-php-sdk/issues/274) +* add `ApplicationStatus` with application status codes description +* add fabric method `AccessToken::initFromPlacementRequest` when application init form placement request ### Changed diff --git a/src/Core/Credentials/AccessToken.php b/src/Core/Credentials/AccessToken.php index 794d13a3..8cefe7d4 100644 --- a/src/Core/Credentials/AccessToken.php +++ b/src/Core/Credentials/AccessToken.php @@ -4,6 +4,9 @@ namespace Bitrix24\SDK\Core\Credentials; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Symfony\Component\HttpFoundation\Request; + /** * Class AccessToken * @@ -74,4 +77,27 @@ public static function initFromArray(array $request): self (int)$request['expires'] ); } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public static function initFromPlacementRequest(Request $request): self + { + $requestFields = $request->request->all(); + if (!array_key_exists('AUTH_ID', $requestFields)) { + throw new InvalidArgumentException('field AUTH_ID not fount in request'); + } + if (!array_key_exists('REFRESH_ID', $requestFields)) { + throw new InvalidArgumentException('field REFRESH_ID not fount in request'); + } + if (!array_key_exists('AUTH_EXPIRES', $requestFields)) { + throw new InvalidArgumentException('field AUTH_EXPIRES not fount in request'); + } + + return new self( + (string)$request->request->get('AUTH_ID'), + (string)$request->request->get('REFRESH_ID'), + $request->request->getInt('AUTH_EXPIRES'), + ); + } } \ No newline at end of file From 979e9994bbe4bd374c8ca44da1e618240b192e57 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 5 Jun 2022 23:53:49 +0300 Subject: [PATCH 334/647] add ApplicationProfile::initFromArray method Signed-off-by: mesilov --- CHANGELOG.md | 1 + src/Core/Credentials/ApplicationProfile.php | 42 +++++++++++++++------ 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4b1885f..4439e12b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ * add `Placements` [add placements support](https://github.com/mesilov/bitrix24-php-sdk/issues/274) * add `ApplicationStatus` with application status codes description * add fabric method `AccessToken::initFromPlacementRequest` when application init form placement request +* add fabric method `ApplicationProfile::initFromArray` when application profile stored in ENV-variables ### Changed diff --git a/src/Core/Credentials/ApplicationProfile.php b/src/Core/Credentials/ApplicationProfile.php index ea5f1f6e..9b8816da 100644 --- a/src/Core/Credentials/ApplicationProfile.php +++ b/src/Core/Credentials/ApplicationProfile.php @@ -4,6 +4,8 @@ namespace Bitrix24\SDK\Core\Credentials; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; + /** * Class ApplicationProfile * @@ -11,18 +13,12 @@ */ class ApplicationProfile { - /** - * @var string - */ - private $clientId; - /** - * @var string - */ - private $clientSecret; - /** - * @var Scope - */ - private $scope; + private const BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID = 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID'; + private const BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET = 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET'; + private const BITRIX24_PHP_SDK_APPLICATION_SCOPE = 'BITRIX24_PHP_SDK_APPLICATION_SCOPE'; + private string $clientId; + private string $clientSecret; + private Scope $scope; /** * ApplicationProfile constructor. @@ -61,4 +57,26 @@ public function getScope(): Scope { return $this->scope; } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public static function initFromArray(array $appProfile): self + { + if (!array_key_exists(self::BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID, $appProfile)) { + throw new InvalidArgumentException(sprintf('in array key %s not found', self::BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID)); + } + if (!array_key_exists(self::BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET, $appProfile)) { + throw new InvalidArgumentException(sprintf('in array key %s not found', self::BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET)); + } + if (!array_key_exists(self::BITRIX24_PHP_SDK_APPLICATION_SCOPE, $appProfile)) { + throw new InvalidArgumentException(sprintf('in array key %s not found', self::BITRIX24_PHP_SDK_APPLICATION_SCOPE)); + } + + return new self( + $appProfile[self::BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID], + $appProfile[self::BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET], + new Scope(str_replace(' ', '', explode(',', $appProfile[self::BITRIX24_PHP_SDK_APPLICATION_SCOPE]))), + ); + } } \ No newline at end of file From 2802c80a63a4086a821873d954c65ea217e3834f Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 5 Jun 2022 23:55:17 +0300 Subject: [PATCH 335/647] add ApplicationProfile::initFromArray method test Signed-off-by: mesilov --- .../Credentials/ApplicationProfileTest.php | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 tests/Unit/Core/Credentials/ApplicationProfileTest.php diff --git a/tests/Unit/Core/Credentials/ApplicationProfileTest.php b/tests/Unit/Core/Credentials/ApplicationProfileTest.php new file mode 100644 index 00000000..a66a38ce --- /dev/null +++ b/tests/Unit/Core/Credentials/ApplicationProfileTest.php @@ -0,0 +1,69 @@ +expectException($expectedException); + } + $prof = ApplicationProfile::initFromArray($arr); + + $this->assertEquals($prof->getClientId(), $arr['BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID']); + $this->assertEquals($prof->getClientSecret(), $arr['BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET']); + } + + public function arrayDataProvider(): Generator + { + yield 'valid' => [ + [ + 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID' => '1', + 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET' => '2', + 'BITRIX24_PHP_SDK_APPLICATION_SCOPE' => 'user', + ], + null, + ]; + yield 'without client id' => [ + [ + '' => '1', + 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET' => '2', + 'BITRIX24_PHP_SDK_APPLICATION_SCOPE' => 'user', + ], + InvalidArgumentException::class, + ]; + yield 'without client secret' => [ + [ + 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID' => '1', + '' => '2', + 'BITRIX24_PHP_SDK_APPLICATION_SCOPE' => 'user', + ], + InvalidArgumentException::class, + ]; + yield 'without client application scope' => [ + [ + 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID' => '1', + 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET' => '2', + '' => 'user', + ], + InvalidArgumentException::class, + ]; + } +} From 2c11a54d27e4e5c25b1656c06273facd64761d28 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 6 Jun 2022 00:27:04 +0300 Subject: [PATCH 336/647] add PlacementRequest Signed-off-by: mesilov --- CHANGELOG.md | 4 +- src/Application/Requests/AbstractRequest.php | 28 +++++ .../Requests/Placement/PlacementRequest.php | 102 ++++++++++++++++++ 3 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 src/Application/Requests/AbstractRequest.php create mode 100644 src/Application/Requests/Placement/PlacementRequest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 4439e12b..330d8836 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,12 @@ ### Added -* add `Placements` [add placements support](https://github.com/mesilov/bitrix24-php-sdk/issues/274) +* WIP!!1111 add `Placements` [add placements support](https://github.com/mesilov/bitrix24-php-sdk/issues/274) +* * add `ApplicationStatus` with application status codes description * add fabric method `AccessToken::initFromPlacementRequest` when application init form placement request * add fabric method `ApplicationProfile::initFromArray` when application profile stored in ENV-variables +* add `Bitrix24\SDK\Application\Requests\Placement\PlacementRequest` for application data from placements ### Changed diff --git a/src/Application/Requests/AbstractRequest.php b/src/Application/Requests/AbstractRequest.php new file mode 100644 index 00000000..be080268 --- /dev/null +++ b/src/Application/Requests/AbstractRequest.php @@ -0,0 +1,28 @@ +request = $request; + } + + /** + * @return \Symfony\Component\HttpFoundation\Request + */ + public function getRequest(): Request + { + return $this->request; + } +} \ No newline at end of file diff --git a/src/Application/Requests/Placement/PlacementRequest.php b/src/Application/Requests/Placement/PlacementRequest.php new file mode 100644 index 00000000..f01a5ecc --- /dev/null +++ b/src/Application/Requests/Placement/PlacementRequest.php @@ -0,0 +1,102 @@ +getRequestUri())['query']; + $queryArgs = []; + parse_str($query, $queryArgs); + $this->domainUrl = sprintf('https://%s', $queryArgs['DOMAIN']); + $this->languageCode = $queryArgs['LANG']; + + $this->accessToken = AccessToken::initFromPlacementRequest($request); + $this->applicationStatus = ApplicationStatus::initFromRequest($request); + $this->memberId = $request->request->get('member_id'); + $this->code = (string)$request->request->get('PLACEMENT'); + + $options = json_decode((string)$request->request->get('PLACEMENT_OPTIONS'), true, 512, JSON_THROW_ON_ERROR); + if ($options === null) { + throw new InvalidArgumentException('invalid data in PLACEMENT_OPTIONS json payload'); + } + $this->placementOptions = $options; + } + + public function getApplicationStatus(): ApplicationStatus + { + return $this->applicationStatus; + } + + /** + * @return string + */ + public function getMemberId(): string + { + return $this->memberId; + } + + /** + * @return \Bitrix24\SDK\Core\Credentials\AccessToken + */ + public function getAccessToken(): AccessToken + { + return $this->accessToken; + } + + /** + * @return string + */ + public function getCode(): string + { + return $this->code; + } + + /** + * @return array|mixed + */ + public function getPlacementOptions() + { + return $this->placementOptions; + } + + /** + * @return mixed|string + */ + public function getDomainUrl() + { + return $this->domainUrl; + } + + /** + * @return mixed|string + */ + public function getLanguageCode() + { + return $this->languageCode; + } +} \ No newline at end of file From 4a5267d1377981dea3ce2705009e22b95a3200d7 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 6 Jun 2022 00:30:12 +0300 Subject: [PATCH 337/647] add Credentials::initFromPlacementRequest Signed-off-by: mesilov --- CHANGELOG.md | 5 +++-- src/Core/Credentials/Credentials.php | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 330d8836..896f5260 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,12 +5,13 @@ ### Added * WIP!!1111 add `Placements` [add placements support](https://github.com/mesilov/bitrix24-php-sdk/issues/274) -* +* * add `ApplicationStatus` with application status codes description * add fabric method `AccessToken::initFromPlacementRequest` when application init form placement request * add fabric method `ApplicationProfile::initFromArray` when application profile stored in ENV-variables * add `Bitrix24\SDK\Application\Requests\Placement\PlacementRequest` for application data from placements - +* add fabric method `Credentials::initFromPlacementRequest` when application init form placement request +* ### Changed * bump `symfony/*` to `6.*` version requirement. diff --git a/src/Core/Credentials/Credentials.php b/src/Core/Credentials/Credentials.php index 862e6764..fcfd68cf 100644 --- a/src/Core/Credentials/Credentials.php +++ b/src/Core/Credentials/Credentials.php @@ -5,6 +5,7 @@ namespace Bitrix24\SDK\Core\Credentials; use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Application\Requests\Placement\PlacementRequest; /** * Class Credentials @@ -129,4 +130,20 @@ public static function createForOAuth(AccessToken $accessToken, ApplicationProfi $domainUrl ); } + + /** + * @param \Bitrix24\SDK\Application\Requests\Placement\PlacementRequest $placementRequest + * @param \Bitrix24\SDK\Core\Credentials\ApplicationProfile $applicationProfile + * + * @return self + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public static function initFromPlacementRequest(PlacementRequest $placementRequest, ApplicationProfile $applicationProfile): self + { + return self::createForOAuth( + $placementRequest->getAccessToken(), + $applicationProfile, + $placementRequest->getDomainUrl() + ); + } } \ No newline at end of file From 01fe2eda0c3d5513ad14f4a33070de3d06f0ac76 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 11 Jun 2022 22:03:24 +0300 Subject: [PATCH 338/647] fix protocol in credentials Signed-off-by: mesilov --- src/Core/Credentials/Credentials.php | 6 ++++ .../Unit/Core/Credentials/CredentialsTest.php | 36 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/src/Core/Credentials/Credentials.php b/src/Core/Credentials/Credentials.php index fcfd68cf..05c7f8bd 100644 --- a/src/Core/Credentials/Credentials.php +++ b/src/Core/Credentials/Credentials.php @@ -39,6 +39,12 @@ public function __construct( $this->accessToken = $accessToken; $this->applicationProfile = $applicationProfile; + if ($domainUrl !== null) { + $parseResult = parse_url($domainUrl); + if (!array_key_exists('scheme', $parseResult)) { + $domainUrl = 'https://' . $domainUrl; + } + } if (($domainUrl !== null) && filter_var($domainUrl, FILTER_VALIDATE_URL) === false) { throw new InvalidArgumentException(sprintf('domain URL %s is invalid', $domainUrl)); } diff --git a/tests/Unit/Core/Credentials/CredentialsTest.php b/tests/Unit/Core/Credentials/CredentialsTest.php index 748c3b43..2d061673 100644 --- a/tests/Unit/Core/Credentials/CredentialsTest.php +++ b/tests/Unit/Core/Credentials/CredentialsTest.php @@ -29,6 +29,42 @@ public function testGetDomainUrl( $this->assertEquals($expectedDomainUrl, $credentials->getDomainUrl()); } + /** + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @throws \Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException + */ + public function testDomainUrlWithoutProtocol(): void + { + $credentials = Credentials::createForOAuth( + new AccessToken('', '', 0), + new ApplicationProfile('', '', new Scope(['crm'])), + 'bitrix24-php-sdk-playground.bitrix24.ru' + ); + $this->assertEquals( + 'https://bitrix24-php-sdk-playground.bitrix24.ru', + $credentials->getDomainUrl() + ); + } + + /** + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @throws \Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException + */ + public function testDomainUrlWithProtocol(): void + { + $credentials = Credentials::createForOAuth( + new AccessToken('', '', 0), + new ApplicationProfile('', '', new Scope(['crm'])), + 'https://bitrix24-php-sdk-playground.bitrix24.ru' + ); + $this->assertEquals( + 'https://bitrix24-php-sdk-playground.bitrix24.ru', + $credentials->getDomainUrl() + ); + } + /** * @return \Generator * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException From 515e0ea8b9b9c55cdb971734fd231ac021b9d864 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 12 Jun 2022 00:59:19 +0300 Subject: [PATCH 339/647] add placement suppott Signed-off-by: mesilov --- .../Requests/Placement/PlacementRequest.php | 4 + .../Placement/PlacementServiceBuilder.php | 23 +++ .../Placement/Result/PlacementBindResult.php | 20 +++ .../Result/PlacementLocationCodesResult.php | 19 +++ .../Result/PlacementLocationItemResult.php | 19 +++ .../Result/PlacementUnbindResult.php | 20 +++ .../PlacementsLocationInformationResult.php | 25 +++ src/Services/Placement/Service/Placement.php | 98 ++++++++++++ .../Service/PlacementLocationCode.php | 147 ++++++++++++++++++ src/Services/ServiceBuilder.php | 13 ++ 10 files changed, 388 insertions(+) create mode 100644 src/Services/Placement/PlacementServiceBuilder.php create mode 100644 src/Services/Placement/Result/PlacementBindResult.php create mode 100644 src/Services/Placement/Result/PlacementLocationCodesResult.php create mode 100644 src/Services/Placement/Result/PlacementLocationItemResult.php create mode 100644 src/Services/Placement/Result/PlacementUnbindResult.php create mode 100644 src/Services/Placement/Result/PlacementsLocationInformationResult.php create mode 100644 src/Services/Placement/Service/Placement.php create mode 100644 src/Services/Placement/Service/PlacementLocationCode.php diff --git a/src/Application/Requests/Placement/PlacementRequest.php b/src/Application/Requests/Placement/PlacementRequest.php index f01a5ecc..36b242f1 100644 --- a/src/Application/Requests/Placement/PlacementRequest.php +++ b/src/Application/Requests/Placement/PlacementRequest.php @@ -44,6 +44,10 @@ 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; } diff --git a/src/Services/Placement/PlacementServiceBuilder.php b/src/Services/Placement/PlacementServiceBuilder.php new file mode 100644 index 00000000..0d96bf47 --- /dev/null +++ b/src/Services/Placement/PlacementServiceBuilder.php @@ -0,0 +1,23 @@ +serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Placement($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } +} \ No newline at end of file diff --git a/src/Services/Placement/Result/PlacementBindResult.php b/src/Services/Placement/Result/PlacementBindResult.php new file mode 100644 index 00000000..39d98fa5 --- /dev/null +++ b/src/Services/Placement/Result/PlacementBindResult.php @@ -0,0 +1,20 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Placement/Result/PlacementLocationCodesResult.php b/src/Services/Placement/Result/PlacementLocationCodesResult.php new file mode 100644 index 00000000..f1876fd0 --- /dev/null +++ b/src/Services/Placement/Result/PlacementLocationCodesResult.php @@ -0,0 +1,19 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData(); + } +} \ No newline at end of file diff --git a/src/Services/Placement/Result/PlacementLocationItemResult.php b/src/Services/Placement/Result/PlacementLocationItemResult.php new file mode 100644 index 00000000..4b3b829b --- /dev/null +++ b/src/Services/Placement/Result/PlacementLocationItemResult.php @@ -0,0 +1,19 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData()['count']; + } +} \ No newline at end of file diff --git a/src/Services/Placement/Result/PlacementsLocationInformationResult.php b/src/Services/Placement/Result/PlacementsLocationInformationResult.php new file mode 100644 index 00000000..e24590a4 --- /dev/null +++ b/src/Services/Placement/Result/PlacementsLocationInformationResult.php @@ -0,0 +1,25 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { + $res[] = new PlacementLocationItemResult($item); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/Placement/Service/Placement.php b/src/Services/Placement/Service/Placement.php new file mode 100644 index 00000000..c7bdd416 --- /dev/null +++ b/src/Services/Placement/Service/Placement.php @@ -0,0 +1,98 @@ +core->call( + 'placement.bind', + [ + 'PLACEMENT' => $placementCode, + 'HANDLER' => $handlerUrl, + 'LANG_ALL' => $lang, + ] + ) + ); + } + + /** + * Deletes the registered embedding location handler. Shall be executed with the available account administrative privileges. + * + * @param string $placementCode + * @param string|null $handlerUrl + * + * @return \Bitrix24\SDK\Services\Placement\Result\PlacementUnbindResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/application_embedding/metods/placement_unbind.php + */ + public function unbind(string $placementCode, ?string $handlerUrl): PlacementUnbindResult + { + return new PlacementUnbindResult( + $this->core->call( + 'placement.unbind', + [ + 'PLACEMENT' => $placementCode, + 'HANDLER' => $handlerUrl, + ] + ) + ); + } + + /** + * This method is used to retrieve the list of embedding locations, available to the application. + * + * @param string|null $applicationScopeCode + * + * @return PlacementLocationCodesResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/application_embedding/metods/placement_list.php + */ + public function list(?string $applicationScopeCode = null): PlacementLocationCodesResult + { + return new PlacementLocationCodesResult( + $this->core->call('placement.list', [ + 'SCOPE' => $applicationScopeCode, + ]) + ); + } + + /** + * This method is used to retrieve the list of registered handlers for embedding locations. + * + * @return PlacementsLocationInformationResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/application_embedding/metods/placement_get.php + */ + public function get(): PlacementsLocationInformationResult + { + return new PlacementsLocationInformationResult($this->core->call('placement.get')); + } +} \ No newline at end of file diff --git a/src/Services/Placement/Service/PlacementLocationCode.php b/src/Services/Placement/Service/PlacementLocationCode.php new file mode 100644 index 00000000..eff44c42 --- /dev/null +++ b/src/Services/Placement/Service/PlacementLocationCode.php @@ -0,0 +1,147 @@ +serviceCache[__METHOD__]; } + + /** + * @return PlacementServiceBuilder + */ + public function getPlacementScope(): PlacementServiceBuilder + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new PlacementServiceBuilder($this->core, $this->batch, $this->bulkItemsReader, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } } \ No newline at end of file From e8c6996fac5c4521afacf4a5ddf26276dfa39726 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 12 Jun 2022 11:38:59 +0300 Subject: [PATCH 340/647] add placement fix Signed-off-by: mesilov --- src/Services/Placement/Service/Placement.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Services/Placement/Service/Placement.php b/src/Services/Placement/Service/Placement.php index c7bdd416..f27fd63f 100644 --- a/src/Services/Placement/Service/Placement.php +++ b/src/Services/Placement/Service/Placement.php @@ -4,11 +4,9 @@ namespace Bitrix24\SDK\Services\Placement\Service; -use Bitrix24\SDK\Core\Response\Response; 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\PlacementLocationInformationResult; use Bitrix24\SDK\Services\Placement\Result\PlacementsLocationInformationResult; use Bitrix24\SDK\Services\Placement\Result\PlacementUnbindResult; @@ -51,7 +49,7 @@ public function bind(string $placementCode, string $handlerUrl, array $lang): Pl * @throws \Bitrix24\SDK\Core\Exceptions\TransportException * @link https://training.bitrix24.com/rest_help/application_embedding/metods/placement_unbind.php */ - public function unbind(string $placementCode, ?string $handlerUrl): PlacementUnbindResult + public function unbind(string $placementCode, ?string $handlerUrl = null): PlacementUnbindResult { return new PlacementUnbindResult( $this->core->call( From fd63bd19950529b712fa7358ac6f8b4dd0d1859d Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 12 Jun 2022 16:55:12 +0300 Subject: [PATCH 341/647] add userfieldtype Signed-off-by: mesilov --- CHANGELOG.md | 2 +- .../Placement/PlacementServiceBuilder.php | 13 +++ .../Placement/Result/DeleteUserTypeResult.php | 20 ++++ .../Result/RegisterUserTypeResult.php | 20 ++++ .../Result/UserFieldTypeItemResult.php | 17 +++ .../Placement/Result/UserFieldTypesResult.php | 24 ++++ .../Placement/Service/UserFieldType.php | 106 ++++++++++++++++++ 7 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 src/Services/Placement/Result/DeleteUserTypeResult.php create mode 100644 src/Services/Placement/Result/RegisterUserTypeResult.php create mode 100644 src/Services/Placement/Result/UserFieldTypeItemResult.php create mode 100644 src/Services/Placement/Result/UserFieldTypesResult.php create mode 100644 src/Services/Placement/Service/UserFieldType.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 896f5260..ed8114b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ ### Added * WIP!!1111 add `Placements` [add placements support](https://github.com/mesilov/bitrix24-php-sdk/issues/274) -* +* add `Placement\Service\UserFieldType` service for work with user fields embedding * add `ApplicationStatus` with application status codes description * add fabric method `AccessToken::initFromPlacementRequest` when application init form placement request * add fabric method `ApplicationProfile::initFromArray` when application profile stored in ENV-variables diff --git a/src/Services/Placement/PlacementServiceBuilder.php b/src/Services/Placement/PlacementServiceBuilder.php index 0d96bf47..22b838be 100644 --- a/src/Services/Placement/PlacementServiceBuilder.php +++ b/src/Services/Placement/PlacementServiceBuilder.php @@ -6,6 +6,7 @@ use Bitrix24\SDK\Services\AbstractServiceBuilder; use Bitrix24\SDK\Services\Placement\Service\Placement; +use Bitrix24\SDK\Services\Placement\Service\UserFieldType; class PlacementServiceBuilder extends AbstractServiceBuilder { @@ -20,4 +21,16 @@ public function placement(): Placement return $this->serviceCache[__METHOD__]; } + + /** + * @return \Bitrix24\SDK\Services\Placement\Service\UserFieldType + */ + public function userfieldtype(): UserFieldType + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new UserFieldType($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } } \ No newline at end of file diff --git a/src/Services/Placement/Result/DeleteUserTypeResult.php b/src/Services/Placement/Result/DeleteUserTypeResult.php new file mode 100644 index 00000000..4b785316 --- /dev/null +++ b/src/Services/Placement/Result/DeleteUserTypeResult.php @@ -0,0 +1,20 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Placement/Result/RegisterUserTypeResult.php b/src/Services/Placement/Result/RegisterUserTypeResult.php new file mode 100644 index 00000000..dee044e8 --- /dev/null +++ b/src/Services/Placement/Result/RegisterUserTypeResult.php @@ -0,0 +1,20 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Placement/Result/UserFieldTypeItemResult.php b/src/Services/Placement/Result/UserFieldTypeItemResult.php new file mode 100644 index 00000000..4ed69497 --- /dev/null +++ b/src/Services/Placement/Result/UserFieldTypeItemResult.php @@ -0,0 +1,17 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { + $res[] = new UserFieldTypeItemResult($item); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/Placement/Service/UserFieldType.php b/src/Services/Placement/Service/UserFieldType.php new file mode 100644 index 00000000..c37c8c2f --- /dev/null +++ b/src/Services/Placement/Service/UserFieldType.php @@ -0,0 +1,106 @@ +core->call( + 'userfieldtype.add', + [ + 'USER_TYPE_ID' => $userTypeId, + 'HANDLER' => $handlerUrl, + 'TITLE' => $title, + 'DESCRIPTION' => $description, + ] + ) + ); + } + + /** + * Retrieves list of user field types, registrered by the application. List method. Results in the list of field types with page-by-page navigation. + * + * @return UserFieldTypesResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/application_embedding/user_field/userfieldtype_list.php + */ + public function list(): UserFieldTypesResult + { + return new UserFieldTypesResult( + $this->core->call('userfieldtype.list') + ); + } + + /** + * Modifies settings of user field types, registered by the application. This method returns true or an error with description. + * + * @param string $userTypeId Inline code of the type. Required parameter. a-z0-9 + * @param string $handlerUrl Address of user type handler. Required parameter. Shall be in the same domain as the main application address. + * @param string $title Type text name. Will be displayed in the admin interface of user field settings. + * @param string $description Type text description. Will be displayed in the admin interface of user field settings. + * + * @return \Bitrix24\SDK\Services\Placement\Result\RegisterUserTypeResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/application_embedding/user_field/userfieldtype_update.php + */ + public function update(string $userTypeId, string $handlerUrl, string $title, string $description): RegisterUserTypeResult + { + return new RegisterUserTypeResult( + $this->core->call( + 'userfieldtype.update', + [ + 'USER_TYPE_ID' => $userTypeId, + 'HANDLER' => $handlerUrl, + 'TITLE' => $title, + 'DESCRIPTION' => $description, + ] + ) + ); + } + + /** + * Deletes user field type, registered by the application. This method returns true or an error with description. + * + * @param string $userTypeId Inline code of the type. Required parameter. a-z0-9 + * + * @return \Bitrix24\SDK\Services\Placement\Result\DeleteUserTypeResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/application_embedding/user_field/userfieldtype_delete.php + */ + public function delete(string $userTypeId): DeleteUserTypeResult + { + return new DeleteUserTypeResult( + $this->core->call( + 'userfieldtype.delete', + [ + 'USER_TYPE_ID' => $userTypeId, + ] + ) + ); + } +} \ No newline at end of file From d50951978cdb645e48830e1a72a80dfaca2bd36d Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 12 Jun 2022 17:33:37 +0300 Subject: [PATCH 342/647] update CHANGELOG.md Signed-off-by: mesilov --- CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3ec5d1b..ef202fa2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,16 +1,16 @@ # bitrix24-php-sdk change log -## 2.0-alpha.7 — 02.05.2022 +## 2.0-alpha.7 — 13.06.2022 - -### Changed -* update scope list [расширить и актуализировать доступные скоупы](https://github.com/mesilov/bitrix24-php-sdk/issues/280) ### Added * add method `Core\Batch::updateEntityItems` for [update items in batch mode](https://github.com/mesilov/bitrix24-php-sdk/issues/268) and integration test * add method to interface `Core\Contracts\BatchInterface::updateEntityItems` for update items in batch mode * add in scope «CRM» `Services\CRM\Deal\Service\Batch::update` batch update deals +### Changed +* update scope list [расширить и актуализировать доступные скоупы](https://github.com/mesilov/bitrix24-php-sdk/issues/280) + ## 2.0-alpha.6 — 7.02.2021 ### Added From 6d863c3cd2c328051288e7966c4c792399e67169 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 12 Jun 2022 21:00:45 +0300 Subject: [PATCH 343/647] fix tests after merge Signed-off-by: mesilov --- tests/Integration/Services/Main/Service/MainTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Integration/Services/Main/Service/MainTest.php b/tests/Integration/Services/Main/Service/MainTest.php index d92aa8a0..ba337d32 100644 --- a/tests/Integration/Services/Main/Service/MainTest.php +++ b/tests/Integration/Services/Main/Service/MainTest.php @@ -40,13 +40,13 @@ public function testGetCurrentScope(): void } /** - * @covers Bitrix24\SDK\Services\Main\Service\Main::getAvailableMethods + * @covers \Bitrix24\SDK\Services\Main\Service\Main::getAvailableMethods * @testdox test methods list * @return void * @throws \Bitrix24\SDK\Core\Exceptions\BaseException * @throws \Bitrix24\SDK\Core\Exceptions\TransportException */ - public function testList(): void + public function testGetAvailableMethods(): void { $this->assertIsArray($this->mainService->getAvailableMethods()->getResponseData()->getResult()->getResultData()); } From 5b01cc3f8111c3a01c90349f058b0d94b7b279f0 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 12 Jun 2022 21:08:24 +0300 Subject: [PATCH 344/647] fix serviceBuilder after merge Signed-off-by: mesilov --- src/Services/ServiceBuilder.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Services/ServiceBuilder.php b/src/Services/ServiceBuilder.php index c1f1e1c7..dc42b678 100644 --- a/src/Services/ServiceBuilder.php +++ b/src/Services/ServiceBuilder.php @@ -76,5 +76,4 @@ public function getPlacementScope(): PlacementServiceBuilder return $this->serviceCache[__METHOD__]; } - } \ No newline at end of file From 1a97324672777b0e4d4ecde182537d20c8a42df2 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 13 Jun 2022 14:37:32 +0300 Subject: [PATCH 345/647] add methods to main service Signed-off-by: mesilov --- CHANGELOG.md | 30 ++- .../Requests/Placement/PlacementRequest.php | 3 + src/Core/Batch.php | 4 +- .../Main/Result/ApplicationInfoItemResult.php | 32 +++ .../Main/Result/ApplicationInfoResult.php | 16 ++ .../Main/Result/IsUserAdminResult.php | 20 ++ .../Main/Result/MethodAffordabilityResult.php | 29 +++ src/Services/Main/Result/ServerTimeResult.php | 21 ++ .../Main/Result/UserProfileItemResult.php | 32 +++ .../Main/Result/UserProfileResult.php | 16 ++ src/Services/Main/Service/Main.php | 189 +++++++++++------- .../Services/Main/Service/MainTest.php | 60 +++++- 12 files changed, 367 insertions(+), 85 deletions(-) create mode 100644 src/Services/Main/Result/ApplicationInfoItemResult.php create mode 100644 src/Services/Main/Result/ApplicationInfoResult.php create mode 100644 src/Services/Main/Result/IsUserAdminResult.php create mode 100644 src/Services/Main/Result/MethodAffordabilityResult.php create mode 100644 src/Services/Main/Result/ServerTimeResult.php create mode 100644 src/Services/Main/Result/UserProfileItemResult.php create mode 100644 src/Services/Main/Result/UserProfileResult.php diff --git a/CHANGELOG.md b/CHANGELOG.md index bf93a2d0..d16f1c27 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,30 +4,40 @@ ### Added -* add method `Core\Batch::updateEntityItems` for [update items in batch mode](https://github.com/mesilov/bitrix24-php-sdk/issues/268) and integration test +* add new scope `UserConsent` and services [add UserConsent support](https://github.com/mesilov/bitrix24-php-sdk/issues/285) +* add new scope `Placements` and services [add Placements support](https://github.com/mesilov/bitrix24-php-sdk/issues/274) +* add new service `Leads` in scope «CRM» [add Leads support](https://github.com/mesilov/bitrix24-php-sdk/issues/282) +* add new service `Activity` in scope «CRM» [add Activity support](https://github.com/mesilov/bitrix24-php-sdk/issues/283) +* add method `Core\Batch::updateEntityItems` for [update items in batch mode](https://github.com/mesilov/bitrix24-php-sdk/issues/268) and + integration test * add method to interface `Core\Contracts\BatchInterface::updateEntityItems` for update items in batch mode -* add in scope «CRM» `Services\CRM\Deal\Service\Batch::update` batch update deals -* add `Leads` [добавить поддержку лидов](https://github.com/mesilov/bitrix24-php-sdk/issues/282) -* add CRM Activity support [добавить поддержку дел](https://github.com/mesilov/bitrix24-php-sdk/issues/283) -* add in scope «CRM» `Services\CRM\Contact\Service\Batch::delete` batch delete contacts -* add service for work with user consent agreement [добавить поддержку сущности «Соглашения»](https://github.com/mesilov/bitrix24-php-sdk/issues/285) -* add scope `UserConsent` for ServiceBuilder -* add `Placements` [add placements support](https://github.com/mesilov/bitrix24-php-sdk/issues/274) -* add `Placement\Service\UserFieldType` service for work with user fields embedding +* add in scope `CRM` for entity Deal method `Services\CRM\Deal\Service\Batch::update` batch update deals +* add in scope `CRM` for entity Contact method `Services\CRM\Contact\Service\Batch::delete` batch delete contacts +* add in scope `Placements` service `Placement\Service\UserFieldType` for work with user fields embedding * add `ApplicationStatus` with application status codes description * add fabric method `AccessToken::initFromPlacementRequest` when application init form placement request * add fabric method `ApplicationProfile::initFromArray` when application profile stored in ENV-variables * add `Bitrix24\SDK\Application\Requests\Placement\PlacementRequest` for application data from placements * add fabric method `Credentials::initFromPlacementRequest` when application init form placement request +* add method `Services\Main\Service::getServerTime` returns current server time in the format YYYY-MM-DDThh:mm:ss±hh:mm. +* add method `Services\Main\Service::getCurrentUserProfile` return basic Information about the current user without any scopes +* add method `Services\Main\Service::getAccessName` returns access permission names. +* add method `Services\Main\Service::checkUserAccess` Checks if the current user has at least one permission of those specified by the + ACCESS parameter. +* add method `Services\Main\Service::getMethodAffordability` Method returns 2 parameters - isExisting and isAvailable ### Changed + * update scope list [расширить и актуализировать доступные скоупы](https://github.com/mesilov/bitrix24-php-sdk/issues/280) * bump `symfony/*` to `6.*` version requirement. -* fix type compatible errors for `Core\Result\AbstractItem` +* method `Services\Main\Service::getAvailableMethods` marks as deprecated +* method `Services\Main\Service::getAllMethods` marks as deprecated +* method `Services\Main\Service::getMethodsByScope` marks as deprecated ### Bugfix * add bugfix for batch method for reverse order queries +* fix type compatible errors for `Core\Result\AbstractItem` ## 2.0-alpha.6 — 7.02.2022 diff --git a/src/Application/Requests/Placement/PlacementRequest.php b/src/Application/Requests/Placement/PlacementRequest.php index 36b242f1..99e3fb7c 100644 --- a/src/Application/Requests/Placement/PlacementRequest.php +++ b/src/Application/Requests/Placement/PlacementRequest.php @@ -16,6 +16,9 @@ class PlacementRequest extends AbstractRequest private string $memberId; private ApplicationStatus $applicationStatus; private string $code; + /** + * @var array + */ private array $placementOptions; private string $domainUrl; private string $languageCode; diff --git a/src/Core/Batch.php b/src/Core/Batch.php index 28700653..d98288a2 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -173,8 +173,8 @@ public function deleteEntityItems(string $apiMethod, array $entityItemId): Gener * 'params' => [] // optional fields * ] * - * @param string $apiMethod - * @param array $entityItems + * @param string $apiMethod + * @param array> $entityItems * * @return Generator|ResponseData[] * @throws \Bitrix24\SDK\Core\Exceptions\BaseException diff --git a/src/Services/Main/Result/ApplicationInfoItemResult.php b/src/Services/Main/Result/ApplicationInfoItemResult.php new file mode 100644 index 00000000..d76bd1fd --- /dev/null +++ b/src/Services/Main/Result/ApplicationInfoItemResult.php @@ -0,0 +1,32 @@ +STATUS !== null ? new ApplicationStatus($this->STATUS) : null; + } +} \ No newline at end of file diff --git a/src/Services/Main/Result/ApplicationInfoResult.php b/src/Services/Main/Result/ApplicationInfoResult.php new file mode 100644 index 00000000..db41cf23 --- /dev/null +++ b/src/Services/Main/Result/ApplicationInfoResult.php @@ -0,0 +1,16 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData()); + } +} \ No newline at end of file diff --git a/src/Services/Main/Result/IsUserAdminResult.php b/src/Services/Main/Result/IsUserAdminResult.php new file mode 100644 index 00000000..434993f8 --- /dev/null +++ b/src/Services/Main/Result/IsUserAdminResult.php @@ -0,0 +1,20 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Main/Result/MethodAffordabilityResult.php b/src/Services/Main/Result/MethodAffordabilityResult.php new file mode 100644 index 00000000..d15a5fbc --- /dev/null +++ b/src/Services/Main/Result/MethodAffordabilityResult.php @@ -0,0 +1,29 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData()['isExisting']; + } + + /** + * @return bool + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function isAvailable(): bool + { + return $this->getCoreResponse()->getResponseData()->getResult()->getResultData()['isAvailable']; + } +} \ No newline at end of file diff --git a/src/Services/Main/Result/ServerTimeResult.php b/src/Services/Main/Result/ServerTimeResult.php new file mode 100644 index 00000000..04d340fa --- /dev/null +++ b/src/Services/Main/Result/ServerTimeResult.php @@ -0,0 +1,21 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData()[0]); + } +} \ No newline at end of file diff --git a/src/Services/Main/Result/UserProfileItemResult.php b/src/Services/Main/Result/UserProfileItemResult.php new file mode 100644 index 00000000..433a5003 --- /dev/null +++ b/src/Services/Main/Result/UserProfileItemResult.php @@ -0,0 +1,32 @@ +STATUS !== null ? new ApplicationStatus($this->STATUS) : null; + } +} \ No newline at end of file diff --git a/src/Services/Main/Result/UserProfileResult.php b/src/Services/Main/Result/UserProfileResult.php new file mode 100644 index 00000000..a17810a4 --- /dev/null +++ b/src/Services/Main/Result/UserProfileResult.php @@ -0,0 +1,16 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData()); + } +} \ No newline at end of file diff --git a/src/Services/Main/Service/Main.php b/src/Services/Main/Service/Main.php index e49f8bf3..7d4bd720 100644 --- a/src/Services/Main/Service/Main.php +++ b/src/Services/Main/Service/Main.php @@ -8,6 +8,11 @@ use Bitrix24\SDK\Core\Exceptions\TransportException; use Bitrix24\SDK\Core\Response\Response; use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\Main\Result\ApplicationInfoResult; +use Bitrix24\SDK\Services\Main\Result\IsUserAdminResult; +use Bitrix24\SDK\Services\Main\Result\MethodAffordabilityResult; +use Bitrix24\SDK\Services\Main\Result\ServerTimeResult; +use Bitrix24\SDK\Services\Main\Result\UserProfileResult; /** * Class Main @@ -17,137 +22,177 @@ class Main extends AbstractService { /** - * @return Response - * @throws BaseException - * @throws TransportException + * Method returns current server time in the format YYYY-MM-DDThh:mm:ss±hh:mm. + * + * @link https://training.bitrix24.com/rest_help/general/server_time.php + * @return \Bitrix24\SDK\Services\Main\Result\ServerTimeResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException */ - public function getCurrentScope(): Response + public function getServerTime(): ServerTimeResult + { + return new ServerTimeResult($this->core->call('server.time')); + } + + /** + * Allows to return basic Information about the current user without any scopes, in contrast to user.current. + * + * @link https://training.bitrix24.com/rest_help/general/profile.php + * @return \Bitrix24\SDK\Services\Main\Result\UserProfileResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function getCurrentUserProfile(): UserProfileResult { - $this->log->debug('getCurrentScope.start'); + return new UserProfileResult($this->core->call('profile')); + } - $result = $this->core->call('scope'); + /** + * Returns access permission names. + * + * @param array $accessList + * + * @return \Bitrix24\SDK\Core\Response\Response + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/general/access_name.php + */ + public function getAccessName(array $accessList): Response + { + return $this->core->call('access.name', [ + 'ACCESS' => $accessList, + ]); + } - $this->log->debug('getCurrentScope.finish'); + /** + * Checks if the current user has at least one permission of those specified by the ACCESS parameter. + * + * @param array $accessToCheck + * + * @return \Bitrix24\SDK\Core\Response\Response + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/general/user_access.php + */ + public function checkUserAccess(array $accessToCheck): Response + { + return $this->core->call('user.access', [ + 'ACCESS' => $accessToCheck, + ]); + } - return $result; + /** + * Method returns 2 parameters - isExisting and isAvailable + * + * @param string $methodName + * + * @return \Bitrix24\SDK\Services\Main\Result\MethodAffordabilityResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/general/method_get.php + */ + public function getMethodAffordability(string $methodName): MethodAffordabilityResult + { + return new MethodAffordabilityResult( + $this->core->call('method.get', [ + 'name' => $methodName, + ]) + ); } /** + * It will return permissions available to the current application. + * * @return Response * @throws BaseException * @throws TransportException + * @link https://training.bitrix24.com/rest_help/general/scope.php */ - public function getAvailableScope(): Response + public function getCurrentScope(): Response { - $this->log->debug('getAvailableScope.start'); - - $result = $this->core->call('scope', ['full' => true]); - - $this->log->debug('getAvailableScope.finish'); - - return $result; + return $this->core->call('scope'); } /** + * Method will return a list of all possible permissions. + * * @return Response * @throws BaseException * @throws TransportException + * @link https://training.bitrix24.com/rest_help/general/scope.php */ - public function getAvailableMethods(): Response + public function getAvailableScope(): Response { - $this->log->debug('getAvailableMethods.start'); - - $result = $this->core->call('methods', []); - - $this->log->debug('getAvailableMethods.finish'); - - return $result; + return $this->core->call('scope', ['full' => true]); } /** + * Returns the methods available to the current application + * * @return Response * @throws BaseException * @throws TransportException + * @deprecated use method.get + * @link https://training.bitrix24.com/rest_help/general/methods.php */ - public function getAllMethods(): Response + public function getAvailableMethods(): Response { - $this->log->debug('getAllMethods.start'); - - $result = $this->core->call('methods', ['full' => true]); - - $this->log->debug('getAllMethods.finish'); - - return $result; + return $this->core->call('methods', []); } /** - * @param string $scope + * Returns the methods available * * @return Response * @throws BaseException * @throws TransportException + * @deprecated use method.get + * @link https://training.bitrix24.com/rest_help/general/methods.php */ - public function getMethodsByScope(string $scope): Response + public function getAllMethods(): Response { - $this->log->debug( - 'getMethodsByScope.start', - [ - 'scope' => $scope, - ] - ); - - $result = $this->core->call('methods', ['scope' => $scope]); - - $this->log->debug('getMethodsByScope.finish'); - - return $result; + return $this->core->call('methods', ['full' => true]); } /** + * Returns the methods available to the current application + * + * @param string $scope + * * @return Response * @throws BaseException * @throws TransportException + * @deprecated use method.get + * @link https://training.bitrix24.com/rest_help/general/methods.php */ - public function getApplicationInfo(): Response + public function getMethodsByScope(string $scope): Response { - $this->log->debug('getApplicationInfo.start'); - - $result = $this->core->call('app.info'); - - $this->log->debug('getApplicationInfo.finish'); - - return $result; + return $this->core->call('methods', ['scope' => $scope]); } /** - * @return Response + * Displays application information. The method supports secure calling convention. + * + * @return ApplicationInfoResult * @throws BaseException * @throws TransportException + * @link https://training.bitrix24.com/rest_help/general/app_info.php */ - public function isCurrentUserHasAdminRights(): Response + public function getApplicationInfo(): ApplicationInfoResult { - $this->log->debug('isCurrentUserHasAdminRights.start'); - - $result = $this->core->call('user.admin'); - - $this->log->debug('isCurrentUserHasAdminRights.finish'); - - return $result; + return new ApplicationInfoResult($this->core->call('app.info')); } /** - * @return Response + * Checks if a current user has permissions to manage application parameters. + * + * @return IsUserAdminResult * @throws BaseException * @throws TransportException + * @link https://training.bitrix24.com/rest_help/general/user_admin.php */ - public function getUserProfile(): Response + public function isCurrentUserHasAdminRights(): IsUserAdminResult { - $this->log->debug('getUserProfile.start'); - - $result = $this->core->call('profile'); - - $this->log->debug('getUserProfile.finish'); - - return $result; + return new IsUserAdminResult($this->core->call('user.admin')); } } \ No newline at end of file diff --git a/tests/Integration/Services/Main/Service/MainTest.php b/tests/Integration/Services/Main/Service/MainTest.php index ba337d32..afc052b8 100644 --- a/tests/Integration/Services/Main/Service/MainTest.php +++ b/tests/Integration/Services/Main/Service/MainTest.php @@ -13,6 +13,64 @@ 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 + */ + public function testGetServerTime(): void + { + $this->mainService->getServerTime()->time(); + $this->assertTrue(true); + } + + /** + * @covers \Bitrix24\SDK\Services\Main\Service\Main::getCurrentUserProfile + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function testGetCurrentUserProfile(): void + { + $profile = $this->mainService->getCurrentUserProfile()->getUserProfile(); + $this->assertTrue($profile->ADMIN); + } + + /** + * @covers \Bitrix24\SDK\Services\Main\Service\Main::isCurrentUserHasAdminRights + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function testIsUserIsAdmin(): void + { + $this->assertTrue($this->mainService->isCurrentUserHasAdminRights()->isAdmin()); + } + + /** + * @covers \Bitrix24\SDK\Services\Main\Service\Main::getMethodAffordability + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function testMethodGetInformationForNonExistsMethod(): void + { + $this->assertFalse($this->mainService->getMethodAffordability('app.info1')->isAvailable()); + $this->assertFalse($this->mainService->getMethodAffordability('app.info1')->isExisting()); + } + + /** + * @covers \Bitrix24\SDK\Services\Main\Service\Main::getApplicationInfo + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function testApplicationInfo(): void + { + $this->assertIsString($this->mainService->getApplicationInfo()->applicationInfo()->LICENSE); + } + /** * @return void * @throws \Bitrix24\SDK\Core\Exceptions\BaseException @@ -40,7 +98,7 @@ public function testGetCurrentScope(): void } /** - * @covers \Bitrix24\SDK\Services\Main\Service\Main::getAvailableMethods + * @covers \Bitrix24\SDK\Services\Main\Service\Main::getAvailableMethods * @testdox test methods list * @return void * @throws \Bitrix24\SDK\Core\Exceptions\BaseException From f40aca88c215de1f3d745dcdde8e8d90f378ba77 Mon Sep 17 00:00:00 2001 From: mesilov Date: Tue, 14 Jun 2022 10:26:01 +0300 Subject: [PATCH 346/647] fix year Signed-off-by: mesilov --- MIT-LICENSE.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MIT-LICENSE.txt b/MIT-LICENSE.txt index deb1e09d..109e678b 100644 --- a/MIT-LICENSE.txt +++ b/MIT-LICENSE.txt @@ -1,5 +1,4 @@ -Copyright 2013 Mesilov Maxim -https://bitrixinsider.ru/ +Copyright 2022 Maxim Mesilov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the From 1fbcbf58e61c7e3131bfcde3fb2086680e4adbe1 Mon Sep 17 00:00:00 2001 From: mesilov Date: Tue, 21 Jun 2022 22:47:58 +0300 Subject: [PATCH 347/647] fix RenewedAccessToken Signed-off-by: mesilov --- CHANGELOG.md | 1 + src/Core/Core.php | 2 +- src/Core/Response/DTO/RenewedAccessToken.php | 28 +------------------- 3 files changed, 3 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d16f1c27..e137e35e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ * add bugfix for batch method for reverse order queries * fix type compatible errors for `Core\Result\AbstractItem` +* fix error in `RenewedAccessToken` DTO, remove `Scope` enum [UnknownScopeCodeException - in refresh token response](https://github.com/mesilov/bitrix24-php-sdk/issues/295) ## 2.0-alpha.6 — 7.02.2022 diff --git a/src/Core/Core.php b/src/Core/Core.php index f5fb9deb..ee67a93e 100644 --- a/src/Core/Core.php +++ b/src/Core/Core.php @@ -83,7 +83,7 @@ public function call(string $apiMethod, array $parameters = []): Response break; case StatusCodeInterface::STATUS_UNAUTHORIZED: $body = $apiCallResponse->toArray(false); - $this->logger->notice( + $this->logger->debug( 'UNAUTHORIZED request', [ 'body' => $body, diff --git a/src/Core/Response/DTO/RenewedAccessToken.php b/src/Core/Response/DTO/RenewedAccessToken.php index a338c17a..3ed060da 100644 --- a/src/Core/Response/DTO/RenewedAccessToken.php +++ b/src/Core/Response/DTO/RenewedAccessToken.php @@ -15,7 +15,6 @@ class RenewedAccessToken { private AccessToken $accessToken; - private Scope $scope; private string $memberId; private string $clientEndpoint; private string $serverEndpoint; @@ -26,7 +25,6 @@ class RenewedAccessToken * RenewedAccessToken constructor. * * @param AccessToken $accessToken - * @param Scope $scope * @param string $memberId * @param string $clientEndpoint * @param string $serverEndpoint @@ -35,7 +33,6 @@ class RenewedAccessToken */ public function __construct( AccessToken $accessToken, - Scope $scope, string $memberId, string $clientEndpoint, string $serverEndpoint, @@ -43,7 +40,6 @@ public function __construct( string $domain ) { $this->accessToken = $accessToken; - $this->scope = $scope; $this->memberId = $memberId; $this->clientEndpoint = $clientEndpoint; $this->serverEndpoint = $serverEndpoint; @@ -59,14 +55,6 @@ public function getAccessToken(): AccessToken return $this->accessToken; } - /** - * @return Scope - */ - public function getScope(): Scope - { - return $this->scope; - } - /** * @return string */ @@ -111,13 +99,11 @@ public function getDomain(): string * @param array $response * * @return self - * @throws \Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException */ public static function initFromArray(array $response): self { return new self( AccessToken::initFromArray($response), - new Scope(explode(',', (string)$response['scope'])), (string)$response['member_id'], (string)$response['client_endpoint'], (string)$response['server_endpoint'], @@ -125,16 +111,4 @@ public static function initFromArray(array $response): self (string)$response['domain'] ); } -} - -//{ -// "access_token": "s1morf609228iwyjjpvfv6wsvuja4p8u", -// "refresh_token": "4f9k4jpmg13usmybzuqknt2v9fh0q6rl", -// "expires_in": 3600, -// "scope": "app", -// "member_id": "a223c6b3710f85df22e9377d6c4f7553", -// "client_endpoint": "https://portal.bitrix24.com/rest/", -// "server_endpoint": "https://oauth.bitrix.info/rest/", -// "domain": "oauth.bitrix.info", -// "status": "T" -//} \ No newline at end of file +} \ No newline at end of file From 272dce5b570b9bfbc4e8c43fa45ae75747baac63 Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 24 Jun 2022 16:33:56 +0300 Subject: [PATCH 348/647] add Application level events Signed-off-by: mesilov --- CHANGELOG.md | 5 +- .../Requests/Events/AbstractEventRequest.php | 51 +++++++++++++++++++ .../OnApplicationInstall/ApplicationData.php | 17 +++++++ .../Events/OnApplicationInstall/Auth.php | 25 +++++++++ .../OnApplicationInstall.php | 26 ++++++++++ .../ApplicationData.php | 15 ++++++ .../Events/OnApplicationUninstall/Auth.php | 18 +++++++ .../OnApplicationUninstall.php | 26 ++++++++++ 8 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 src/Application/Requests/Events/AbstractEventRequest.php create mode 100644 src/Application/Requests/Events/OnApplicationInstall/ApplicationData.php create mode 100644 src/Application/Requests/Events/OnApplicationInstall/Auth.php create mode 100644 src/Application/Requests/Events/OnApplicationInstall/OnApplicationInstall.php create mode 100644 src/Application/Requests/Events/OnApplicationUninstall/ApplicationData.php create mode 100644 src/Application/Requests/Events/OnApplicationUninstall/Auth.php create mode 100644 src/Application/Requests/Events/OnApplicationUninstall/OnApplicationUninstall.php diff --git a/CHANGELOG.md b/CHANGELOG.md index e137e35e..47029535 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ * add new scope `Placements` and services [add Placements support](https://github.com/mesilov/bitrix24-php-sdk/issues/274) * add new service `Leads` in scope «CRM» [add Leads support](https://github.com/mesilov/bitrix24-php-sdk/issues/282) * add new service `Activity` in scope «CRM» [add Activity support](https://github.com/mesilov/bitrix24-php-sdk/issues/283) +* add support Application level events: `ONAPPINSTALL` + and `ONAPPUNINSTALL` [add incoming events support](https://github.com/mesilov/bitrix24-php-sdk/issues/296) * add method `Core\Batch::updateEntityItems` for [update items in batch mode](https://github.com/mesilov/bitrix24-php-sdk/issues/268) and integration test * add method to interface `Core\Contracts\BatchInterface::updateEntityItems` for update items in batch mode @@ -38,7 +40,8 @@ * add bugfix for batch method for reverse order queries * fix type compatible errors for `Core\Result\AbstractItem` -* fix error in `RenewedAccessToken` DTO, remove `Scope` enum [UnknownScopeCodeException - in refresh token response](https://github.com/mesilov/bitrix24-php-sdk/issues/295) +* fix error in `RenewedAccessToken` DTO, remove `Scope` + enum [UnknownScopeCodeException - in refresh token response](https://github.com/mesilov/bitrix24-php-sdk/issues/295) ## 2.0-alpha.6 — 7.02.2022 diff --git a/src/Application/Requests/Events/AbstractEventRequest.php b/src/Application/Requests/Events/AbstractEventRequest.php new file mode 100644 index 00000000..68d9a3fe --- /dev/null +++ b/src/Application/Requests/Events/AbstractEventRequest.php @@ -0,0 +1,51 @@ +getContent(), $this->eventPayload); + + $this->eventCode = $this->eventPayload['event']; + $this->timestamp = (int)$this->eventPayload['ts']; + } + + /** + * @return int + */ + public function getTimestamp(): int + { + return $this->timestamp; + } + + /** + * @return string + */ + public function getEventCode(): string + { + return $this->eventCode; + } + + /** + * @return array + */ + public function getEventPayload(): array + { + return $this->eventPayload; + } +} \ No newline at end of file diff --git a/src/Application/Requests/Events/OnApplicationInstall/ApplicationData.php b/src/Application/Requests/Events/OnApplicationInstall/ApplicationData.php new file mode 100644 index 00000000..a63186a0 --- /dev/null +++ b/src/Application/Requests/Events/OnApplicationInstall/ApplicationData.php @@ -0,0 +1,17 @@ +eventPayload['data']); + } + + /** + * @return \Bitrix24\SDK\Application\Requests\Events\OnApplicationInstall\Auth + */ + public function getAuth(): Auth + { + return new Auth($this->eventPayload['auth']); + } +} \ No newline at end of file diff --git a/src/Application/Requests/Events/OnApplicationUninstall/ApplicationData.php b/src/Application/Requests/Events/OnApplicationUninstall/ApplicationData.php new file mode 100644 index 00000000..bc49fb2e --- /dev/null +++ b/src/Application/Requests/Events/OnApplicationUninstall/ApplicationData.php @@ -0,0 +1,15 @@ +eventPayload['data']); + } + + /** + * @return \Bitrix24\SDK\Application\Requests\Events\OnApplicationUninstall\Auth + */ + public function getAuth(): Auth + { + return new Auth($this->eventPayload['auth']); + } +} \ No newline at end of file From 82eabff44c188335311e9db398a7abca6ddaf8e4 Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 24 Jun 2022 17:46:12 +0300 Subject: [PATCH 349/647] add Application level events - fix errors Signed-off-by: mesilov --- src/Application/Requests/Events/AbstractEventRequest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Application/Requests/Events/AbstractEventRequest.php b/src/Application/Requests/Events/AbstractEventRequest.php index 68d9a3fe..ca344c96 100644 --- a/src/Application/Requests/Events/AbstractEventRequest.php +++ b/src/Application/Requests/Events/AbstractEventRequest.php @@ -19,7 +19,9 @@ abstract class AbstractEventRequest extends AbstractRequest public function __construct(Request $request) { parent::__construct($request); - parse_str($request->getContent(), $this->eventPayload); + $payload = []; + parse_str($request->getContent(), $payload); + $this->eventPayload = $payload; $this->eventCode = $this->eventPayload['event']; $this->timestamp = (int)$this->eventPayload['ts']; From af28c6b09db101a1290d4cf8f336ac6a1e0e2ec8 Mon Sep 17 00:00:00 2001 From: kirill Date: Wed, 29 Jun 2022 14:40:38 +0300 Subject: [PATCH 350/647] =?UTF-8?q?-=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=B8=D0=BD=D1=81=D1=82=D1=80=D1=83=D0=BA?= =?UTF-8?q?=D1=86=D0=B8=D1=8F=20=D0=BF=D0=BE=20=D1=81=D0=BE=D0=B7=D0=B4?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D1=8E=20=D0=BB=D0=BE=D0=BA=D0=B0=D0=BB=D1=8C?= =?UTF-8?q?=D0=BD=D0=BE=D0=B3=D0=BE=20=D0=BF=D1=80=D0=B8=D0=BB=D0=BE=D0=B6?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/RU/Application/new-local-application.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 docs/RU/Application/new-local-application.md diff --git a/docs/RU/Application/new-local-application.md b/docs/RU/Application/new-local-application.md new file mode 100644 index 00000000..02c9fda6 --- /dev/null +++ b/docs/RU/Application/new-local-application.md @@ -0,0 +1,7 @@ +# Создание Локального приложения +1.Зарегистрируйте новый портал битрикс 24. +2. Включите тестовый период для маркет плейса и тарифного плана. +3. Открой портал и перейдите в меню. + 1. Откройте левое меню выберите "Разработчикам" + 2. Выберите "Другое" + 3. Откройте "Локальное приложение" \ No newline at end of file From 6d86d6d9a47bed3796c684c56ba866531ef85639 Mon Sep 17 00:00:00 2001 From: kirill Date: Wed, 29 Jun 2022 18:05:12 +0300 Subject: [PATCH 351/647] =?UTF-8?q?-=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B8=D0=BD=D1=81=D1=82=D1=80=D1=83=D0=BA=D1=86=D0=B8?= =?UTF-8?q?=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/RU/Application/new-local-application.md | 23 +++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/docs/RU/Application/new-local-application.md b/docs/RU/Application/new-local-application.md index 02c9fda6..2df85e6c 100644 --- a/docs/RU/Application/new-local-application.md +++ b/docs/RU/Application/new-local-application.md @@ -1,7 +1,24 @@ # Создание Локального приложения +## Предусловия +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. 1.Зарегистрируйте новый портал битрикс 24. -2. Включите тестовый период для маркет плейса и тарифного плана. -3. Открой портал и перейдите в меню. +5. Включите тестовый период для маркет плейса и тарифного плана. +6. Открой портал и перейдите в меню. 1. Откройте левое меню выберите "Разработчикам" 2. Выберите "Другое" - 3. Откройте "Локальное приложение" \ No newline at end of file + 3. Откройте "Локальное приложение" + 4. Зарегестрируйте новое локальное приложение с нужным вам скоупом From 3f1df58ac5c33810fe4f210bebdf6fae6cda3a0d Mon Sep 17 00:00:00 2001 From: kirill Date: Thu, 30 Jun 2022 17:00:51 +0300 Subject: [PATCH 352/647] =?UTF-8?q?-=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B8=D0=BD=D1=81=D1=82=D1=80=D1=83=D0=BA=D1=86=D0=B8?= =?UTF-8?q?=D1=8E=20=D0=BF=D0=BE=20(scope=20telephony)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/RU/how-to-add-new-scope/new-scope.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 docs/RU/how-to-add-new-scope/new-scope.md diff --git a/docs/RU/how-to-add-new-scope/new-scope.md b/docs/RU/how-to-add-new-scope/new-scope.md new file mode 100644 index 00000000..c3fd0b38 --- /dev/null +++ b/docs/RU/how-to-add-new-scope/new-scope.md @@ -0,0 +1,9 @@ +# Добавление (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` и ее можно легко найти в интернете. \ No newline at end of file From 3633d0658e588d7e8d23e0e930a0821d17640a75 Mon Sep 17 00:00:00 2001 From: kirill Date: Fri, 1 Jul 2022 18:13:53 +0300 Subject: [PATCH 353/647] =?UTF-8?q?-=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20README.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2656f480..0feecf02 100644 --- a/README.md +++ b/README.md @@ -121,7 +121,8 @@ Add `"mesilov/bitrix24-php-sdk": "2.x"` to `composer.json` of your application. ### Tests -Tests locate in folder `tests` and we have two test types +Tests locate in folder `tests` and we have two test types. +In folder tests create file `.env.local` and fill environment variables from `.env`. #### Unit tests From eb7b4b9bb470f85cdb19d2d33d13ba75f4474888 Mon Sep 17 00:00:00 2001 From: kirill Date: Tue, 5 Jul 2022 16:52:39 +0300 Subject: [PATCH 354/647] =?UTF-8?q?-=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D1=8B=20=D0=BE=D0=BF=D0=B5=D1=87=D0=B0=D1=82?= =?UTF-8?q?=D0=BA=D0=B8=20=D0=B2=20=D0=B8=D0=BD=D1=81=D1=82=D1=80=D1=83?= =?UTF-8?q?=D0=BA=D1=86=D0=B8=D0=B8=20=D0=BF=D0=BE=20=D0=BB=D0=BE=D0=BA?= =?UTF-8?q?=D0=B0=D0=BB=D1=8C=D0=BD=D0=BE=D0=BC=D1=83=20=D0=BF=D1=80=D0=B8?= =?UTF-8?q?=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD=D0=B8=D1=8E.=20-=D0=92=20Service?= =?UTF-8?q?Builder.php=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=20=D0=91=D0=B8=D0=BB=D0=B4=D0=B5=D1=80=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D0=A2=D0=B5=D0=BB=D0=B5=D1=84=D0=BE=D0=BD=D0=B8=D0=B8.=20-?= =?UTF-8?q?=D0=92=20PlacementLocationCode.php=20(=D0=B8=D0=B7=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=BE:=20//=20Telephony=20scope->=20//Extern?= =?UTF-8?q?alLine=20scope)=3F=3F=3F=20-=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D1=8B=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D1=8B?= =?UTF-8?q?=20(telephony.externalLine.add,telephony.externalLine.get)=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D0=A2=D0=B5=D0=BB=D0=B5=D1=84=D0=BE=D0=BD?= =?UTF-8?q?=D0=B8=D0=B8.=20-=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0=D0=BD=D1=8B=20?= =?UTF-8?q?=D0=B8=D0=BD=D1=82=D0=B5=D0=B3=D1=80=D0=B0=D1=86=D0=B8=D0=BE?= =?UTF-8?q?=D0=BD=D0=BD=D1=8B=D0=B5=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D0=BE=D0=B2?= =?UTF-8?q?=20(telephony.externalLine.add,telephony.externalLine.get)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/RU/Application/new-local-application.md | 4 +- .../Service/PlacementLocationCode.php | 2 +- src/Services/ServiceBuilder.php | 13 +++++ .../Result/ExternalLineAddResult.php | 21 +++++++ .../Telephony/Service/ExternalLine.php | 57 +++++++++++++++++++ .../Telephony/TelephonyServiceBuilder.php | 24 ++++++++ .../Telephony/Service/ExternalLineTest.php | 46 +++++++++++++++ 7 files changed, 164 insertions(+), 3 deletions(-) create mode 100644 src/Services/Telephony/Result/ExternalLineAddResult.php create mode 100644 src/Services/Telephony/Service/ExternalLine.php create mode 100644 src/Services/Telephony/TelephonyServiceBuilder.php create mode 100644 tests/Integration/Services/Telephony/Service/ExternalLineTest.php diff --git a/docs/RU/Application/new-local-application.md b/docs/RU/Application/new-local-application.md index 2df85e6c..9116e620 100644 --- a/docs/RU/Application/new-local-application.md +++ b/docs/RU/Application/new-local-application.md @@ -4,7 +4,7 @@ 2. Содержимое файла `install.php`. ```php ``` -3. Для работы локального серверного приложения требуется рабочий веб сервер на маишне разработчика. +3. Для работы локального серверного приложения требуется рабочий веб сервер на машине разработчика. 4. Запускаем локальный веб-сервер, например так: ```shell php -S 127.0.0.1:8080 @@ -13,7 +13,7 @@ php -S 127.0.0.1:8080 ```shell ngrok http 127.0.0.1:8080 ``` -4. После запуска ngrok будет выдан временный публичный адрес типо `https://7949-178-34-183-66.eu.ngrok.io`, который после выключения сервиса перестанет существовать. Этот адрес будет исчезнет после завершения ngrok. +4. После запуска ngrok будет выдан временный публичный адрес типо `https://7949-178-34-183-66.eu.ngrok.io`, который после выключения сервиса перестанет существовать. Этот адрес исчезнет после завершения ngrok. 5. 1.Зарегистрируйте новый портал битрикс 24. 5. Включите тестовый период для маркет плейса и тарифного плана. diff --git a/src/Services/Placement/Service/PlacementLocationCode.php b/src/Services/Placement/Service/PlacementLocationCode.php index eff44c42..6602e5bf 100644 --- a/src/Services/Placement/Service/PlacementLocationCode.php +++ b/src/Services/Placement/Service/PlacementLocationCode.php @@ -72,7 +72,7 @@ class PlacementLocationCode public const CRM_DETAIL_SEARCH = 'CRM_DETAIL_SEARCH'; - // Telephony scope + // ExternalLine scope public const CALL_CARD = 'CALL_CARD'; // Call ID screen public const TELEPHONY_ANALYTICS_MENU = 'TELEPHONY_ANALYTICS_MENU'; diff --git a/src/Services/ServiceBuilder.php b/src/Services/ServiceBuilder.php index dc42b678..830cd9dd 100644 --- a/src/Services/ServiceBuilder.php +++ b/src/Services/ServiceBuilder.php @@ -7,6 +7,7 @@ use Bitrix24\SDK\Services\CRM\CRMServiceBuilder; use Bitrix24\SDK\Services\IM\IMServiceBuilder; use Bitrix24\SDK\Services\Main\MainServiceBuilder; +use Bitrix24\SDK\Services\Telephony\TelephonyServiceBuilder; use Bitrix24\SDK\Services\UserConsent\UserConsentServiceBuilder; use Bitrix24\SDK\Services\Placement\PlacementServiceBuilder; @@ -76,4 +77,16 @@ public function getPlacementScope(): PlacementServiceBuilder return $this->serviceCache[__METHOD__]; } + + /** + * @return TelephonyServiceBuilder + */ + public function getTelephonyScope(): TelephonyServiceBuilder + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new TelephonyServiceBuilder($this->core, $this->batch, $this->bulkItemsReader, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } } \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalLineAddResult.php b/src/Services/Telephony/Result/ExternalLineAddResult.php new file mode 100644 index 00000000..580a924f --- /dev/null +++ b/src/Services/Telephony/Result/ExternalLineAddResult.php @@ -0,0 +1,21 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData(); + } + +} \ No newline at end of file diff --git a/src/Services/Telephony/Service/ExternalLine.php b/src/Services/Telephony/Service/ExternalLine.php new file mode 100644 index 00000000..88ac6b73 --- /dev/null +++ b/src/Services/Telephony/Service/ExternalLine.php @@ -0,0 +1,57 @@ +core->call( + 'telephony.externalLine.add', + [ + 'NUMBER' => $number, + 'NAME' => $name, + ] + ) + ); + } + + /** + * The method adds an outer line + * + * @return \Bitrix24\SDK\Services\Telephony\Result\ExternalLineAddResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://dev.1c-bitrix.ru/rest_help/scope_telephony/telephony/telephony_externalLine_get.php + */ + + public function get(): ExternalLineAddResult + { + return new ExternalLineAddResult( + $this->core->call( + 'telephony.externalLine.get', + [ + + ] + ) + ); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/TelephonyServiceBuilder.php b/src/Services/Telephony/TelephonyServiceBuilder.php new file mode 100644 index 00000000..955249a3 --- /dev/null +++ b/src/Services/Telephony/TelephonyServiceBuilder.php @@ -0,0 +1,24 @@ +serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new ExternalLine($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + +} \ No newline at end of file diff --git a/tests/Integration/Services/Telephony/Service/ExternalLineTest.php b/tests/Integration/Services/Telephony/Service/ExternalLineTest.php new file mode 100644 index 00000000..24b078bc --- /dev/null +++ b/tests/Integration/Services/Telephony/Service/ExternalLineTest.php @@ -0,0 +1,46 @@ +externalLineService->add('79117654321','newline')->isSuccess()); + self::assertTrue($this->externalLineService->add('79117654321','newline')->isSuccess()); + + } + + /** + * * @throws BaseException + * @throws TransportException + * @covers ExternalLine::get + */ + public function testGet(): void + { + self::assertTrue((bool)$this->externalLineService->get()->getCoreResponse()->getResponseData()->getResult()->getResultData()); + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public function setUp(): void + { + $this->externalLineService = Fabric::getServiceBuilder()->getTelephonyScope()->externalline(); + } + +} \ No newline at end of file From cf18109f40264b10eedba5e50736589d5ec9020a Mon Sep 17 00:00:00 2001 From: kirill Date: Wed, 6 Jul 2022 13:21:33 +0300 Subject: [PATCH 355/647] -Add ExternalLine Service --- .../Result/ExternalLineAddResult.php | 9 +++---- .../Result/ExternalLineItemResult.php | 17 +++++++++++++ .../Telephony/Result/ExternalLinesResult.php | 24 +++++++++++++++++++ .../Telephony/Service/ExternalLine.php | 21 ++++++++-------- .../Telephony/Service/ExternalLineTest.php | 8 ++++--- 5 files changed, 62 insertions(+), 17 deletions(-) create mode 100644 src/Services/Telephony/Result/ExternalLineItemResult.php create mode 100644 src/Services/Telephony/Result/ExternalLinesResult.php diff --git a/src/Services/Telephony/Result/ExternalLineAddResult.php b/src/Services/Telephony/Result/ExternalLineAddResult.php index 580a924f..8542bf7a 100644 --- a/src/Services/Telephony/Result/ExternalLineAddResult.php +++ b/src/Services/Telephony/Result/ExternalLineAddResult.php @@ -4,18 +4,19 @@ 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 +class ExternalLineAddResult extends AbstractResult implements AddedItemIdResultInterface { /** - * @return bool + * @return int * @throws BaseException */ - public function isSuccess(): bool + public function getId(): int { - return (bool)$this->getCoreResponse()->getResponseData()->getResult()->getResultData(); + return $this->getCoreResponse()->getResponseData()->getResult()->getResultData()['ID']; } } \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalLineItemResult.php b/src/Services/Telephony/Result/ExternalLineItemResult.php new file mode 100644 index 00000000..8edf51f3 --- /dev/null +++ b/src/Services/Telephony/Result/ExternalLineItemResult.php @@ -0,0 +1,17 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { + $res[] = new ExternalLineItemResult($item); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Service/ExternalLine.php b/src/Services/Telephony/Service/ExternalLine.php index 88ac6b73..4fbe6027 100644 --- a/src/Services/Telephony/Service/ExternalLine.php +++ b/src/Services/Telephony/Service/ExternalLine.php @@ -6,29 +6,30 @@ use Bitrix24\SDK\Services\AbstractService; use Bitrix24\SDK\Services\Telephony\Result\ExternalLineAddResult; +use Bitrix24\SDK\Services\Telephony\Result\ExternalLinesResult; class ExternalLine extends AbstractService{ /** * The method adds an outer line * - * @param string $number - * @param string $name + * @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://dev.1c-bitrix.ru/rest_help/scope_telephony/telephony/telephony_externalLine_add.php + * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalLine_add.php */ - public function add(string $number , string $name): ExternalLineAddResult + public function add(string $lineNumber , string $nameLine): ExternalLineAddResult { return new ExternalLineAddResult( $this->core->call( 'telephony.externalLine.add', [ - 'NUMBER' => $number, - 'NAME' => $name, + 'NUMBER' => $lineNumber, + 'NAME' => $nameLine, ] ) ); @@ -37,15 +38,15 @@ public function add(string $number , string $name): ExternalLineAddResult /** * The method adds an outer line * - * @return \Bitrix24\SDK\Services\Telephony\Result\ExternalLineAddResult + * @return ExternalLinesResult * @throws \Bitrix24\SDK\Core\Exceptions\BaseException * @throws \Bitrix24\SDK\Core\Exceptions\TransportException - * @link https://dev.1c-bitrix.ru/rest_help/scope_telephony/telephony/telephony_externalLine_get.php + * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalLine_get.php */ - public function get(): ExternalLineAddResult + public function get(): ExternalLinesResult { - return new ExternalLineAddResult( + return new ExternalLinesResult( $this->core->call( 'telephony.externalLine.get', [ diff --git a/tests/Integration/Services/Telephony/Service/ExternalLineTest.php b/tests/Integration/Services/Telephony/Service/ExternalLineTest.php index 24b078bc..e84277fe 100644 --- a/tests/Integration/Services/Telephony/Service/ExternalLineTest.php +++ b/tests/Integration/Services/Telephony/Service/ExternalLineTest.php @@ -20,8 +20,7 @@ class ExternalLineTest extends TestCase { */ public function testAdd(): void { - // self::assertEquals(1, $this->externalLineService->add('79117654321','newline')->isSuccess()); - self::assertTrue($this->externalLineService->add('79117654321','newline')->isSuccess()); + self::assertGreaterThan(1,$this->externalLineService->add((string)time(),sprintf('phpUnit-%s',time()))->getId()); } @@ -32,7 +31,10 @@ public function testAdd(): void */ public function testGet(): void { - self::assertTrue((bool)$this->externalLineService->get()->getCoreResponse()->getResponseData()->getResult()->getResultData()); + + $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()); } /** From 4125641fd8cb016002bc6e715564f947aa97c8a5 Mon Sep 17 00:00:00 2001 From: kirill Date: Wed, 6 Jul 2022 18:56:26 +0300 Subject: [PATCH 356/647] =?UTF-8?q?-=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B4=D0=BE=D0=BA=D1=83=D0=BC=D0=B5=D0=BD=D1=82=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D1=8E.=20-=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BD=D0=BE=D0=B2=D1=8B=D0=B5=20=D0=BC=D0=B5=D1=82?= =?UTF-8?q?=D0=BE=D0=B4=D1=8B=20=D0=B4=D0=BB=D1=8F=20=D1=82=D0=B5=D0=BB?= =?UTF-8?q?=D0=B5=D1=84=D0=BE=D0=BD=D0=B8=D0=B8.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + docs/RU/how-to-add-new-scope/new-scope.md | 10 +++- .../Telephony/Service/ExternalLine.php | 56 +++++++++++++++++++ .../Telephony/Service/ExternalLineTest.php | 55 +++++++++++++++++- 4 files changed, 117 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 7c3db918..f5140f0e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /.idea* +/app vendor composer.phar composer.lock diff --git a/docs/RU/how-to-add-new-scope/new-scope.md b/docs/RU/how-to-add-new-scope/new-scope.md index c3fd0b38..4acc8132 100644 --- a/docs/RU/how-to-add-new-scope/new-scope.md +++ b/docs/RU/how-to-add-new-scope/new-scope.md @@ -5,5 +5,11 @@ 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` и ее можно легко найти в интернете. \ No newline at end of file +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 будут размещены сервисы с их методами. + 3. В папке Result будут размещены результаты наших методов(то что они будут возвращать). + 4. Также в папке `src/Services/Telephony` размещаем TelephonyServiceBuilder.php. Этот сервис нужен для подключения нашего скоупа с тестами. +6. После того как мы добавили наши методы для работы с Телефонией нужно их затестить. Создадим в папке `tests/Integration/Services/Telephony/Service/` наши тесты и проверим все ли работает как надо ExternalLineTest.php. \ No newline at end of file diff --git a/src/Services/Telephony/Service/ExternalLine.php b/src/Services/Telephony/Service/ExternalLine.php index 4fbe6027..522abcb7 100644 --- a/src/Services/Telephony/Service/ExternalLine.php +++ b/src/Services/Telephony/Service/ExternalLine.php @@ -7,6 +7,8 @@ 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{ @@ -55,4 +57,58 @@ public function get(): ExternalLinesResult ) ); } + + /** + * The method allows you to change the name of the external line + * + * @param string $lineNumber + * @param string $nameLine + * + * @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 $nameLine): ExternalLineUpdateResult + { + /* var_dump($this->core->call('telephony.externalLine.update', + [ + 'NUMBER'=>$lineNumber, + 'NAME'=>$nameLine, + ] + ) + ->getResponseData()->getResult()->getResultData() + );exit();*/ + return new ExternalLineUpdateResult( + $this->core->call('telephony.externalLine.update', + [ + 'NUMBER'=>$lineNumber, + 'NAME'=>$nameLine, + ] + ) + ); + } + + /** + * 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/tests/Integration/Services/Telephony/Service/ExternalLineTest.php b/tests/Integration/Services/Telephony/Service/ExternalLineTest.php index e84277fe..2e2dc9a1 100644 --- a/tests/Integration/Services/Telephony/Service/ExternalLineTest.php +++ b/tests/Integration/Services/Telephony/Service/ExternalLineTest.php @@ -31,12 +31,61 @@ public function testAdd(): void */ public function testGet(): void { - - $this->externalLineService->add((string)time(),sprintf('phpUnit-%s',time())); - $this->externalLineService->add((string)time(),sprintf('phpUnit-%s',time())); + // $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 + * @covers ExternalLine::update + */ + public function testUpdateExternalLineName():void + { + + //$lineNameBefore = array((string)time() => sprintf('phpUnit-%s',time())); + $lineNumber = (string)time(); + $lineNameBefore = sprintf('phpUnit-%s',time()); + + self::assertGreaterThan(1,$this->externalLineService->add($lineNumber,$lineNameBefore)->getId()); + $externalLineNameBefore = array_column($this->externalLineService->get()->getExternalLines(),'NAME'); + var_dump($externalLineNameBefore); + + $lineNameAfter = sprintf('phpUnit-%s-second',time()); + $this->externalLineService->update($lineNumber,$lineNameAfter)->updateExternalLineId(); + $externalLineNameAfter = array_column($this->externalLineService->get()->getExternalLines(),'NAME'); + var_dump($externalLineNameAfter); + self::assertFalse(in_array($lineNameBefore,$externalLineNameAfter),sprintf('expected update %s line name see %s name',$lineNameBefore,$lineNameAfter)); + + /* + self::assertGreaterThan(1,$this->externalLineService->add('8765890978','oldName')->getId()); + self::assertGreaterThan(1,$this->externalLineService->update('8765890978','newTestLine')->updateExternalLineId()); + self::assertGreaterThan(1,$this->externalLineService->get()->getExternalLines()); + */ + } + + /** + * @throws BaseException + * @throws TransportException + * @covers ExternalLine::delete + */ + public function testDelete():void + { + $lineNumber = (string)time().(string)random_int(1,PHP_INT_MAX); +var_dump($lineNumber); + 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]; + var_dump(array_values(array_diff($externalLineNumbersBefore,$externalLineNumbersAfter))); + self::assertEquals($lineNumber,$deletedLineNumber,sprintf('expected deleted %s number see %s number',$lineNumber,$deletedLineNumber)); + } + + /** * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException */ From 9ba276c04079b61605d6b01de858877fb1019896 Mon Sep 17 00:00:00 2001 From: kirill Date: Wed, 6 Jul 2022 18:59:10 +0300 Subject: [PATCH 357/647] =?UTF-8?q?-=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20Result=20=D0=B4=D0=BB=D1=8F=20=D0=BC=D0=B5=D1=82=D0=BE?= =?UTF-8?q?=D0=B4=D0=BE=D0=B2=20Delete=20and=20Update.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Result/ExternalLineDeleteResult.php | 12 +++++++++++ .../Result/ExternalLineUpdateResult.php | 20 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 src/Services/Telephony/Result/ExternalLineDeleteResult.php create mode 100644 src/Services/Telephony/Result/ExternalLineUpdateResult.php diff --git a/src/Services/Telephony/Result/ExternalLineDeleteResult.php b/src/Services/Telephony/Result/ExternalLineDeleteResult.php new file mode 100644 index 00000000..b780c507 --- /dev/null +++ b/src/Services/Telephony/Result/ExternalLineDeleteResult.php @@ -0,0 +1,12 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData()['ID']; + } +} \ No newline at end of file From 64a1acfc51c83a58ecff3f060be710a3d3e17c7f Mon Sep 17 00:00:00 2001 From: kirill Date: Thu, 7 Jul 2022 16:33:16 +0300 Subject: [PATCH 358/647] =?UTF-8?q?=D0=9D=D0=B0=D1=87=D0=B0=D0=BB=20=D1=80?= =?UTF-8?q?=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=BE=D0=B2=D1=8B=D0=B2=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20telephony.externalcall.register.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Result/ExternalCallRegisterItemResult.php | 20 ++++ .../Result/ExternalCallRegisterResult.php | 26 +++++ .../Telephony/Service/ExternalCall.php | 102 ++++++++++++++++++ .../Telephony/Service/ExternalLine.php | 8 -- .../Telephony/TelephonyServiceBuilder.php | 13 +++ .../Telephony/Service/ExternalCallTest.php | 74 +++++++++++++ 6 files changed, 235 insertions(+), 8 deletions(-) create mode 100644 src/Services/Telephony/Result/ExternalCallRegisterItemResult.php create mode 100644 src/Services/Telephony/Result/ExternalCallRegisterResult.php create mode 100644 src/Services/Telephony/Service/ExternalCall.php create mode 100644 tests/Integration/Services/Telephony/Service/ExternalCallTest.php diff --git a/src/Services/Telephony/Result/ExternalCallRegisterItemResult.php b/src/Services/Telephony/Result/ExternalCallRegisterItemResult.php new file mode 100644 index 00000000..76c4cdd9 --- /dev/null +++ b/src/Services/Telephony/Result/ExternalCallRegisterItemResult.php @@ -0,0 +1,20 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { + $res[] = new ExternalCallRegisterItemResult($item); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Service/ExternalCall.php b/src/Services/Telephony/Service/ExternalCall.php new file mode 100644 index 00000000..f41d4211 --- /dev/null +++ b/src/Services/Telephony/Service/ExternalCall.php @@ -0,0 +1,102 @@ +core->call( + 'telephony.externalcall.register', + [ + 'USER_PHONE_INNER'=>$userPhoneInner, + 'USER_ID'=>$userId, + 'PHONE_NUMBER'=>$userPhoneNumber, + 'CALL_START_DATE'=>$callStartDate, + 'CRM_CREATE'=>$crmCreate, + 'CRM_SOURCE'=>$crmSource, + 'USER_ENTITY_TYPE'=>$crmEntityType, + 'CRM_ENTITY_ID'=>$crmEntityId, + 'SHOW'=>$showCardCall, + 'CALL_LIST_ID'=>$callListId, + 'LINE_NUMBER'=>$outsideLineNumber, + 'TYPE'=>$typeCall, + ] + ) + ->getResponseData()->getResult()->getResultData() + );exit();*/ + + return new ExternalCallRegisterResult( + $this->core->call( + 'telephony.externalcall.register', + [ + 'USER_PHONE_INNER'=>$userPhoneInner, + 'USER_ID'=>$userId, + 'PHONE_NUMBER'=>$userPhoneNumber, + 'CALL_START_DATE'=>$callStartDate, + 'CRM_CREATE'=>$crmCreate, + 'CRM_SOURCE'=>$crmSource, + 'USER_ENTITY_TYPE'=>$crmEntityType, + 'CRM_ENTITY_ID'=>$crmEntityId, + 'SHOW'=>$showCardCall, + 'CALL_LIST_ID'=>$callListId, + 'LINE_NUMBER'=>$outsideLineNumber, + 'TYPE'=>$typeCall, + ] + ) + ); + } + + /** + * This method displays a call ID screen to the user. + * + * + * @param string $callId + * @param int $userId + * + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @return \Bitrix24\SDK\Services\Telephony\Result\ExternalCallShowResult + * + * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_show.php + */ + public function showCallCard(string $callId, int $userId):ExternalCallShowResult{ + return new ExternalCallShowResult( + $this->core->call( + 'telephony.externalcall.show', + [ + 'CALL_ID'=>$callId, + 'USER_ID'=>$userId, + ] + ) + ); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Service/ExternalLine.php b/src/Services/Telephony/Service/ExternalLine.php index 522abcb7..9158fb58 100644 --- a/src/Services/Telephony/Service/ExternalLine.php +++ b/src/Services/Telephony/Service/ExternalLine.php @@ -72,14 +72,6 @@ public function get(): ExternalLinesResult public function update(string $lineNumber , string $nameLine): ExternalLineUpdateResult { - /* var_dump($this->core->call('telephony.externalLine.update', - [ - 'NUMBER'=>$lineNumber, - 'NAME'=>$nameLine, - ] - ) - ->getResponseData()->getResult()->getResultData() - );exit();*/ return new ExternalLineUpdateResult( $this->core->call('telephony.externalLine.update', [ diff --git a/src/Services/Telephony/TelephonyServiceBuilder.php b/src/Services/Telephony/TelephonyServiceBuilder.php index 955249a3..72660f4c 100644 --- a/src/Services/Telephony/TelephonyServiceBuilder.php +++ b/src/Services/Telephony/TelephonyServiceBuilder.php @@ -5,6 +5,7 @@ use Bitrix24\SDK\Services\AbstractServiceBuilder; use Bitrix24\SDK\Services\Telephony\Service\ExternalLine; +use Bitrix24\SDK\Services\Telephony\Service\ExternalCall; class TelephonyServiceBuilder extends AbstractServiceBuilder @@ -21,4 +22,16 @@ public function externalline(): ExternalLine 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__]; + } + } \ No newline at end of file diff --git a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php new file mode 100644 index 00000000..208f6bd5 --- /dev/null +++ b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php @@ -0,0 +1,74 @@ +format(DateTimeInterface::ATOM); + + + $crmCreate = 1; + //1-звонок + $crmSource = 1; + + + $masType = array('CONTACT','COMPANY','LEAD'); + $randWord = array_rand($masType); + $crmEntityType = $masType[$randWord]; + + $crmEntityId = $randWord; + + + $showCard = 1; + $callListId = random_int(0,1000000); + $lineNumber = (string)strtotime("+5 day"); + $typeCall = random_int(1,4); + + // Тест + self::assertGreaterThan(1,$this->externalCallService->register_call($userPhoneInner,$userId,$phoneNumber,$callStartDate,$crmCreate,$crmSource,$crmEntityType, + $crmEntityId,$showCard,$callListId,$lineNumber,$typeCall)->getExternalCallRegister()); + } + /** + * @throws BaseException + * @throws TransportException + * @throws \Exception + * @covers ExternalCall::showCallCard + */ + public function testShowCallCard():void{ + + } + /** + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public function setUp(): void + { + $this->externalCallService = Fabric::getServiceBuilder()->getTelephonyScope()->externalCall(); + } +} \ No newline at end of file From 5f3bb62a2968eb97f1a6a23e965247f1d986006c Mon Sep 17 00:00:00 2001 From: kirill Date: Fri, 8 Jul 2022 16:29:31 +0300 Subject: [PATCH 359/647] =?UTF-8?q?=D0=9D=D0=B0=D1=87=D0=B0=D0=BB=20=D1=80?= =?UTF-8?q?=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=BE=D0=B2=D1=8B=D0=B2=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20telephony.externalcall.register.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Result/ExternalCallFinishResult.php | 20 ++ .../Result/ExternalCallHideResult.php | 20 ++ .../Result/ExternalCallRecordResult.php | 19 ++ .../Result/ExternalCallRegisterResult.php | 9 +- .../Result/ExternalCallShowResult.php | 20 ++ .../Telephony/Service/ExternalCall.php | 119 +++++++-- .../Telephony/Service/ExternalCallTest.php | 239 +++++++++++++++++- .../Telephony/Service/ExternalLineTest.php | 9 +- 8 files changed, 407 insertions(+), 48 deletions(-) create mode 100644 src/Services/Telephony/Result/ExternalCallFinishResult.php create mode 100644 src/Services/Telephony/Result/ExternalCallHideResult.php create mode 100644 src/Services/Telephony/Result/ExternalCallRecordResult.php create mode 100644 src/Services/Telephony/Result/ExternalCallShowResult.php diff --git a/src/Services/Telephony/Result/ExternalCallFinishResult.php b/src/Services/Telephony/Result/ExternalCallFinishResult.php new file mode 100644 index 00000000..fdffb465 --- /dev/null +++ b/src/Services/Telephony/Result/ExternalCallFinishResult.php @@ -0,0 +1,20 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData(); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalCallHideResult.php b/src/Services/Telephony/Result/ExternalCallHideResult.php new file mode 100644 index 00000000..1cc8fb4b --- /dev/null +++ b/src/Services/Telephony/Result/ExternalCallHideResult.php @@ -0,0 +1,20 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData(); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalCallRecordResult.php b/src/Services/Telephony/Result/ExternalCallRecordResult.php new file mode 100644 index 00000000..cb44487e --- /dev/null +++ b/src/Services/Telephony/Result/ExternalCallRecordResult.php @@ -0,0 +1,19 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData(); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalCallRegisterResult.php b/src/Services/Telephony/Result/ExternalCallRegisterResult.php index 1921afd9..26d45be7 100644 --- a/src/Services/Telephony/Result/ExternalCallRegisterResult.php +++ b/src/Services/Telephony/Result/ExternalCallRegisterResult.php @@ -10,17 +10,12 @@ class ExternalCallRegisterResult extends AbstractResult { /** - * @return ExternalCallRegisterItemResult[] + * @return array * @throws \Bitrix24\SDK\Core\Exceptions\BaseException */ public function getExternalCallRegister(): array { - $res = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { - $res[] = new ExternalCallRegisterItemResult($item); - } - - return $res; + return $this->getCoreResponse()->getResponseData()->getResult()->getResultData(); } } \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalCallShowResult.php b/src/Services/Telephony/Result/ExternalCallShowResult.php new file mode 100644 index 00000000..2ef78a66 --- /dev/null +++ b/src/Services/Telephony/Result/ExternalCallShowResult.php @@ -0,0 +1,20 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData(); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Service/ExternalCall.php b/src/Services/Telephony/Service/ExternalCall.php index f41d4211..48874983 100644 --- a/src/Services/Telephony/Service/ExternalCall.php +++ b/src/Services/Telephony/Service/ExternalCall.php @@ -5,7 +5,10 @@ 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\ExternalCallShowResult; @@ -34,25 +37,6 @@ class ExternalCall extends AbstractService{ public function register_call(string $userPhoneInner, int $userId, string $userPhoneNumber, string $callStartDate, int $crmCreate, int $crmSource, string $crmEntityType,int $crmEntityId, int $showCardCall,int $callListId, string $outsideLineNumber, int $typeCall): ExternalCallRegisterResult { - /* var_dump($this->core->call( - 'telephony.externalcall.register', - [ - 'USER_PHONE_INNER'=>$userPhoneInner, - 'USER_ID'=>$userId, - 'PHONE_NUMBER'=>$userPhoneNumber, - 'CALL_START_DATE'=>$callStartDate, - 'CRM_CREATE'=>$crmCreate, - 'CRM_SOURCE'=>$crmSource, - 'USER_ENTITY_TYPE'=>$crmEntityType, - 'CRM_ENTITY_ID'=>$crmEntityId, - 'SHOW'=>$showCardCall, - 'CALL_LIST_ID'=>$callListId, - 'LINE_NUMBER'=>$outsideLineNumber, - 'TYPE'=>$typeCall, - ] - ) - ->getResponseData()->getResult()->getResultData() - );exit();*/ return new ExternalCallRegisterResult( $this->core->call( @@ -82,10 +66,10 @@ public function register_call(string $userPhoneInner, int $userId, string $userP * @param string $callId * @param int $userId * - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException * @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 showCallCard(string $callId, int $userId):ExternalCallShowResult{ @@ -99,4 +83,97 @@ public function showCallCard(string $callId, int $userId):ExternalCallShowResult ) ); } + + /** + * 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 hideCallCard(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 string $callId + * @param int $userId + * @param int $durationCall + * @param float $costCall + * @param string $costCurrency + * @param string $statusCode + * @param string $failedReason + * @param string $recordUrlFile + * @param int $vote + * @param int $addMessageToChat + * + * @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_call(string $callId, int $userId, int $durationCall, float $costCall, string $costCurrency, + string $statusCode, string $failedReason, string $recordUrlFile, int $vote, int $addMessageToChat):ExternalCallFinishResult + { + return new ExternalCallFinishResult( + $this->core->call( + 'telephony.externalcall.finish', + [ + 'CALL_ID'=>$callId, + 'USER_ID'=>$userId, + 'DURATION'=>$durationCall, + 'COST'=>$costCall, + 'COST_CURRENCY'=>$costCurrency, + 'STATUS_CODE'=>$statusCode, + 'FAILED_REASON'=>$failedReason, + 'RECORD_URL'=>$recordUrlFile, + 'VOTE'=>$vote, + 'ADD_TO_CHAT'=>$addMessageToChat, + ] + ) + ); + } + + /** + * 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 $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):ExternalCallRecordResult + { + return new ExternalCallRecordResult( + $this->core->call( + 'telephony.externalCall.attachRecord', + [ + 'CALL_ID'=>$callId, + 'FILENAME'=>$fileName, + 'FILE_CONTENT'=>$fileContent, + 'RECORD_URL'=>$recordUrl, + ] + ) + ); + } } \ No newline at end of file diff --git a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php index 208f6bd5..94f83554 100644 --- a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php +++ b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php @@ -25,44 +25,257 @@ public function testRegisterCall():void { //Подготовка данных - $userPhoneInner = sprintf('+%s',time()); - //$userId = (int)strtotime("+1 day"); + //Внутренний номер пользователя. + $userPhoneInner = '+79788045002'; + //Идентификатор пользователя. $userId = 1; + //Номер с которого звоним. $phoneNumber = '+79788045001'; - + //Дата/время звонка (string)$datetime = new DateTime('now'); $callStartDate = $datetime->format(DateTimeInterface::ATOM); + //[0/1] - Автоматическое создание в CRM сущности, связанной со звонком. + $crmCreate = 1; + //1-звонок + $crmSource = 1; + //Тип объекта CRM, из карточки которого совершается звонок + /* $masType = array('CONTACT','COMPANY','LEAD'); + $randWord = array_rand($masType); + $crmEntityType = $masType[$randWord];*/ + //Не уверен, что правильно + $crmEntityType = 'COMPANY'; + $crmEntityId = 1; + //Показывать карточку или нет. + $showCard = 1; + //Идентификатор списка обзвона, к которому должен быть привязан звонок. (ГДЕ НАЙТИ СПИСОК ОБЗВОНА???) + $callListId = 1; + //Номер на который поступает звонок + $lineNumber = '+79767867656'; + /* Обязательный. Тип звонка: + 1 - исходящий + 2 - входящий + 3 - входящий с перенаправлением + 4 - обратный*/ + $typeCall = 1; + // Тест + self::assertGreaterThan(1,$this->externalCallService->register_call($userPhoneInner,$userId,$phoneNumber,$callStartDate,$crmCreate,$crmSource,$crmEntityType, + $crmEntityId,$showCard,$callListId,$lineNumber,$typeCall)->getExternalCallRegister()); + } + /** + * @throws BaseException + * @throws TransportException + * @throws \Exception + * @covers ExternalCall::showCallCard + */ + public function testShowCallCard():void{ + //Внутренний номер пользователя. + $userPhoneInner = '+79788045002'; + //Идентификатор пользователя. + $userId = 1; + //Номер с которого звоним. + $phoneNumber = '+79788045001'; + //Дата/время звонка + (string)$datetime = new DateTime('now'); + $callStartDate = $datetime->format(DateTimeInterface::ATOM); + //[0/1] - Автоматическое создание в CRM сущности, связанной со звонком. $crmCreate = 1; //1-звонок $crmSource = 1; + //Тип объекта CRM, из карточки которого совершается звонок + $masType = array('CONTACT','COMPANY','LEAD'); + $randWord = array_rand($masType); + $crmEntityType = $masType[$randWord]; + $crmEntityId = $randWord; + //Не уверен, что правильно + // $crmEntityType = 'COMPANY'; + // $crmEntityId = 1; + //Показывать карточку или нет. + $showCard = 1; + //Идентификатор списка обзвона, к которому должен быть привязан звонок. (ГДЕ НАЙТИ СПИСОК ОБЗВОНА???) + $callListId = 1; + //Номер на который поступает звонок + $lineNumber = '+79767867658'; + /* Обязательный. Тип звонка: + 1 - исходящий + 2 - входящий + 3 - входящий с перенаправлением + 4 - обратный*/ + $typeCall = 4; + $res = []; + $res=$this->externalCallService->register_call($userPhoneInner,$userId,$phoneNumber,$callStartDate,$crmCreate,$crmSource,$crmEntityType, $crmEntityId,$showCard,$callListId,$lineNumber,$typeCall)->getExternalCallRegister(); + self::assertGreaterThan(1,$this->externalCallService->showCallCard($res['CALL_ID'],1)->getExternalCalls()); + } + /** + * @throws BaseException + * @throws TransportException + * @throws \Exception + * @covers ExternalCall::hideCallCard + */ + public function testHideCallCard():void{ + //Внутренний номер пользователя. + $userPhoneInner = '+79788045002'; + //Идентификатор пользователя. + $userId = 1; + //Номер с которого звоним. + $phoneNumber = '+79788045001'; + //Дата/время звонка + (string)$datetime = new DateTime('now'); + $callStartDate = $datetime->format(DateTimeInterface::ATOM); + //[0/1] - Автоматическое создание в CRM сущности, связанной со звонком. + $crmCreate = 1; + //1-звонок + $crmSource = 1; + //Тип объекта CRM, из карточки которого совершается звонок $masType = array('CONTACT','COMPANY','LEAD'); $randWord = array_rand($masType); $crmEntityType = $masType[$randWord]; - $crmEntityId = $randWord; + //Не уверен, что правильно + // $crmEntityType = 'COMPANY'; + // $crmEntityId = 1; + //Показывать карточку или нет. + $showCard = 1; + //Идентификатор списка обзвона, к которому должен быть привязан звонок. (ГДЕ НАЙТИ СПИСОК ОБЗВОНА???) + $callListId = 1; + //Номер на который поступает звонок + $lineNumber = '+79767867658'; + /* Обязательный. Тип звонка: + 1 - исходящий + 2 - входящий + 3 - входящий с перенаправлением + 4 - обратный*/ + $typeCall = 4; + $res = []; + $res=$this->externalCallService->register_call($userPhoneInner,$userId,$phoneNumber,$callStartDate,$crmCreate,$crmSource,$crmEntityType, $crmEntityId,$showCard,$callListId,$lineNumber,$typeCall)->getExternalCallRegister(); + self::assertGreaterThan(1,$this->externalCallService->hideCallCard($res['CALL_ID'],1)->getExternalHideCalls()); + } + /** + * @throws TransportException + * @throws BaseException + * @throws \Exception + * @covers ExternalCall::finish_call + */ + public function testFinishCall():void{ + //Внутренний номер пользователя. + $userPhoneInner = '+79788045002'; + //Идентификатор пользователя. + $userId = 1; + //Номер с которого звоним. + $phoneNumber = '+79788045001'; + //Дата/время звонка + (string)$datetime = new DateTime('now'); + $callStartDate = $datetime->format(DateTimeInterface::ATOM); + //[0/1] - Автоматическое создание в CRM сущности, связанной со звонком. + $crmCreate = 1; + //1-звонок + $crmSource = 1; + //Тип объекта CRM, из карточки которого совершается звонок + $masType = array('CONTACT','COMPANY','LEAD'); + $randWord = array_rand($masType); + $crmEntityType = $masType[$randWord]; + $crmEntityId = $randWord; + //Не уверен, что правильно + // $crmEntityType = 'COMPANY'; + // $crmEntityId = 1; + //Показывать карточку или нет. $showCard = 1; - $callListId = random_int(0,1000000); - $lineNumber = (string)strtotime("+5 day"); - $typeCall = random_int(1,4); + //Идентификатор списка обзвона, к которому должен быть привязан звонок. (ГДЕ НАЙТИ СПИСОК ОБЗВОНА???) + $callListId = 1; + //Номер на который поступает звонок + $lineNumber = '+79767867658'; + /* Обязательный. Тип звонка: + 1 - исходящий + 2 - входящий + 3 - входящий с перенаправлением + 4 - обратный*/ + $typeCall = 2; - // Тест - self::assertGreaterThan(1,$this->externalCallService->register_call($userPhoneInner,$userId,$phoneNumber,$callStartDate,$crmCreate,$crmSource,$crmEntityType, - $crmEntityId,$showCard,$callListId,$lineNumber,$typeCall)->getExternalCallRegister()); + $res = []; + $res=$this->externalCallService->register_call($userPhoneInner,$userId,$phoneNumber,$callStartDate,$crmCreate,$crmSource,$crmEntityType, $crmEntityId,$showCard,$callListId,$lineNumber,$typeCall)->getExternalCallRegister(); + + //Подготовка + $call_id = $res['CALL_ID']; + $user_Id = 1; + $duration = 255; + $cost = 5000; + $cosy_currency = 'RUB'; + $status_code = 'VI_STATUS_304'; + $failed_reason = ''; + $record_url = ''; + $vote = 5; + $add_to_chat = 1; + self::assertGreaterThan(1,$this->externalCallService->finish_call($call_id,$user_Id,$duration,$cost,$cosy_currency,$status_code,$failed_reason,$record_url,$vote,$add_to_chat)->getFinishCallResult()); } + /** - * @throws BaseException * @throws TransportException + * @throws BaseException * @throws \Exception - * @covers ExternalCall::showCallCard + * @covers ExternalCall::attachRecord */ - public function testShowCallCard():void{ + public function testRecordCall():void + { + //Внутренний номер пользователя. + $userPhoneInner = '+79788045002'; + //Идентификатор пользователя. + $userId = 1; + //Номер с которого звоним. + $phoneNumber = '+79788045001'; + //Дата/время звонка + (string)$datetime = new DateTime('now'); + $callStartDate = $datetime->format(DateTimeInterface::ATOM); + //[0/1] - Автоматическое создание в CRM сущности, связанной со звонком. + $crmCreate = 1; + //1-звонок + $crmSource = 1; + //Тип объекта CRM, из карточки которого совершается звонок + $masType = array('CONTACT','COMPANY','LEAD'); + $randWord = array_rand($masType); + $crmEntityType = $masType[$randWord]; + $crmEntityId = $randWord; + //Не уверен, что правильно + // $crmEntityType = 'COMPANY'; + // $crmEntityId = 1; + //Показывать карточку или нет. + $showCard = 1; + //Идентификатор списка обзвона, к которому должен быть привязан звонок. (ГДЕ НАЙТИ СПИСОК ОБЗВОНА???) + $callListId = 1; + //Номер на который поступает звонок + $lineNumber = '+79767867658'; + /* Обязательный. Тип звонка: + 1 - исходящий + 2 - входящий + 3 - входящий с перенаправлением + 4 - обратный*/ + $typeCall = 2; + + $res = []; + $res=$this->externalCallService->register_call($userPhoneInner,$userId,$phoneNumber,$callStartDate,$crmCreate,$crmSource,$crmEntityType, $crmEntityId,$showCard,$callListId,$lineNumber,$typeCall)->getExternalCallRegister(); + + //Подготовка + $call_id = $res['CALL_ID']; + $user_Id = 1; + $duration = 255; + $cost = 5000; + $cosy_currency = 'RUB'; + $status_code = 'VI_STATUS_304'; + $failed_reason = ''; + $record_url = ''; + $vote = 5; + $add_to_chat = 1; + $this->externalCallService->finish_call($call_id,$user_Id,$duration,$cost,$cosy_currency,$status_code,$failed_reason,$record_url,$vote,$add_to_chat)->getFinishCallResult(); + $fileName = 'testFiless'; + //Декодирование в base64 разобраться с этим. + $content = 'filesss'; + $url = 'https://vk.com/audio172690992_456241726_c88e19185934f5b9dd'; + self::assertGreaterThan(1,$this->externalCallService->attachRecord($call_id,$fileName,$content,$url)->getRecord()); } /** * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException diff --git a/tests/Integration/Services/Telephony/Service/ExternalLineTest.php b/tests/Integration/Services/Telephony/Service/ExternalLineTest.php index 2e2dc9a1..7ce7c5f7 100644 --- a/tests/Integration/Services/Telephony/Service/ExternalLineTest.php +++ b/tests/Integration/Services/Telephony/Service/ExternalLineTest.php @@ -58,11 +58,6 @@ public function testUpdateExternalLineName():void var_dump($externalLineNameAfter); self::assertFalse(in_array($lineNameBefore,$externalLineNameAfter),sprintf('expected update %s line name see %s name',$lineNameBefore,$lineNameAfter)); - /* - self::assertGreaterThan(1,$this->externalLineService->add('8765890978','oldName')->getId()); - self::assertGreaterThan(1,$this->externalLineService->update('8765890978','newTestLine')->updateExternalLineId()); - self::assertGreaterThan(1,$this->externalLineService->get()->getExternalLines()); - */ } /** @@ -73,7 +68,7 @@ public function testUpdateExternalLineName():void public function testDelete():void { $lineNumber = (string)time().(string)random_int(1,PHP_INT_MAX); -var_dump($lineNumber); + self::assertGreaterThan(1,$this->externalLineService->add($lineNumber,sprintf('phpUnit-%s',time()))->getId()); $externalLineNumbersBefore = array_column($this->externalLineService->get()->getExternalLines(),'NUMBER'); @@ -81,7 +76,7 @@ public function testDelete():void $externalLineNumbersAfter = array_column($this->externalLineService->get()->getExternalLines(),'NUMBER'); $deletedLineNumber = array_values(array_diff($externalLineNumbersBefore,$externalLineNumbersAfter))[0]; - var_dump(array_values(array_diff($externalLineNumbersBefore,$externalLineNumbersAfter))); + // var_dump(array_values(array_diff($externalLineNumbersBefore,$externalLineNumbersAfter))); self::assertEquals($lineNumber,$deletedLineNumber,sprintf('expected deleted %s number see %s number',$lineNumber,$deletedLineNumber)); } From 475e2950906e7743f6272990d65a636c899cdec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Mon, 11 Jul 2022 10:46:44 +0300 Subject: [PATCH 360/647] -fix error in NetworkTimingParser.php --- CHANGELOG.md | 2 +- .../TransportLayer/NetworkTimingsParser.php | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e137e35e..bdec92c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,7 +39,7 @@ * add bugfix for batch method for reverse order queries * fix type compatible errors for `Core\Result\AbstractItem` * fix error in `RenewedAccessToken` DTO, remove `Scope` enum [UnknownScopeCodeException - in refresh token response](https://github.com/mesilov/bitrix24-php-sdk/issues/295) - +* fix error in `NetworkTimingParser`, [error in NetworkTimingsErrorInfo](https://github.com/mesilov/bitrix24-php-sdk/issues/277) ## 2.0-alpha.6 — 7.02.2022 ### Added diff --git a/src/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser.php b/src/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser.php index 696a08a9..af6b3fef 100644 --- a/src/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser.php +++ b/src/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser.php @@ -21,19 +21,19 @@ public function __construct(array $httpClientResponseInfo) // time_starttransfer: 0.092s // ---------- // time_total: 0.164s - + var_dump($httpClientResponseInfo); $this->networkTimings = [ // name lookup time in MICROSECONDS // https://curl.se/libcurl/c/CURLINFO_NAMELOOKUP_TIME.html // get the name lookup time // Time from the start until the name resolving was completed. // When a redirect is followed, the time from each request is added together. - 'namelookup_time_us' => $httpClientResponseInfo['namelookup_time_us'], + 'namelookup_time' => $httpClientResponseInfo['namelookup_time'], // total time in seconds from the start until the connection to the remote host (or proxy) was completed in MICROSECONDS // https://curl.se/libcurl/c/CURLINFO_CONNECT_TIME.html // When a redirect is followed, the time from each request is added together. - 'connect_time_us' => $httpClientResponseInfo['connect_time_us'], + 'connect_time' => $httpClientResponseInfo['connect_time'], // time until the SSL/SSH handshake is completed in MICROSECONDS // https://curl.se/libcurl/c/CURLINFO_APPCONNECT_TIME.html @@ -41,7 +41,7 @@ public function __construct(array $httpClientResponseInfo) // This time is most often close to the CURLINFO_PRETRANSFER_TIME time, except for cases such as HTTP pipelining // where the pretransfer time can be delayed due to waits in line for the pipeline and more. // When a redirect is followed, the time from each request is added together. - 'appconnect_time_us' => $httpClientResponseInfo['appconnect_time_us'], + 'appconnect_time' => $httpClientResponseInfo['appconnect_time'] ?? null, // time until the file transfer start in MICROSECONDS // https://curl.se/libcurl/c/CURLINFO_PRETRANSFER_TIME.html @@ -49,28 +49,28 @@ public function __construct(array $httpClientResponseInfo) // This time-stamp includes all pre-transfer commands and negotiations that are specific to the particular // protocol(s) involved. It includes the sending of the protocol- specific protocol instructions that triggers a transfer. // When a redirect is followed, the time from each request is added together. - 'pretransfer_time_us' => $httpClientResponseInfo['pretransfer_time_us'], + 'pretransfer_time' => $httpClientResponseInfo['pretransfer_time'], // time for all redirection steps in MICROSECONDS // https://curl.se/libcurl/c/CURLINFO_REDIRECT_TIME.html // it took for all redirection steps include name lookup, connect, pretransfer and transfer before // final transaction was started. // CURLINFO_REDIRECT_TIME contains the complete execution time for multiple redirections. - 'redirect_time_us' => $httpClientResponseInfo['redirect_time_us'], + 'redirect_time' => $httpClientResponseInfo['redirect_time'], // time until the first byte is received in MICROSECONDS // it took from the start until the first byte is received by libcurl // https://curl.se/libcurl/c/CURLINFO_STARTTRANSFER_TIME.html // This includes CURLINFO_PRETRANSFER_TIME and also the time the server needs to calculate the result. // When a redirect is followed, the time from each request is added together. - 'starttransfer_time_us' => $httpClientResponseInfo['starttransfer_time_us'], + 'starttransfer_time' => $httpClientResponseInfo['starttransfer_time'], // total time of previous transfer in MICROSECONDS // https://curl.se/libcurl/c/CURLINFO_TOTAL_TIME.html // total time in seconds for the previous transfer, including name resolving, TCP connect etc. // The double represents the time in seconds, including fractions. // When a redirect is followed, the time from each request is added together. - 'total_time_us' => $httpClientResponseInfo['total_time_us'], + 'total_time' => $httpClientResponseInfo['total_time'], ]; } From 7863da3612e9f2699d65be0394dc0e9805696241 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Mon, 11 Jul 2022 16:35:44 +0300 Subject: [PATCH 361/647] -edit NetworkTimingParser.php --- .../HttpClient/TransportLayer/NetworkTimingsParser.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser.php b/src/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser.php index af6b3fef..093f2a62 100644 --- a/src/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser.php +++ b/src/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser.php @@ -21,7 +21,6 @@ public function __construct(array $httpClientResponseInfo) // time_starttransfer: 0.092s // ---------- // time_total: 0.164s - var_dump($httpClientResponseInfo); $this->networkTimings = [ // name lookup time in MICROSECONDS // https://curl.se/libcurl/c/CURLINFO_NAMELOOKUP_TIME.html From 2895cfb2bc8f4cbd89680b034fcb71ee956fb70d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Mon, 11 Jul 2022 18:59:35 +0300 Subject: [PATCH 362/647] =?UTF-8?q?-=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=20telephony.exter?= =?UTF-8?q?nalcall.register=20-=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D1=84=D0=B0=D0=B9=D0=BB=20CONTRIBUTING.md(=D0=BD?= =?UTF-8?q?=D0=B5=20=D1=80=D0=B5=D0=B4=D0=B0=D0=BA=D1=82=D0=B8=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BB=D1=81=D1=8F)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CONTRIBUTING.md | 39 +++++ .../Result/ExternalCallRegisterResult.php | 8 +- .../Telephony/Service/ExternalCall.php | 47 +++--- .../Telephony/Service/ExternalCallTest.php | 137 +++++++++--------- .../Telephony/Service/ExternalLineTest.php | 4 + 5 files changed, 133 insertions(+), 102 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..47e4633c --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,39 @@ +# A quick guide to contribute to the project: + +## Installing the dev environment + +1. Fork the repo +2. Clone the repo to local +3. Install dependencies: `composer update` (this assumes you have 'composer' aliased to wherever your composer.phar lives) +4. Run the tests. We only take pull requests with passing tests, and it's great to know that you have a clean slate: + `composer test` + +## Adding new features + +Pull requests with new features needs to be created against master branch. + +If new feature require BC Break please note that in your PR comment, it will added in next major version. +New features that does not have any BC Breaks are going to be added in next minor version. + +## Codding standards + +In order to fix codding standards please exeecute: + +``` +composer cs:php:fix +``` + +## Patches and bugfixes + +1. Check the oldest version that patch/bug fix can be applied. +2. Create PR against that version + +For example if you are fixing pattern expander that was introduced in version 1.1 make sure that PR with fix +is created against version 1.1, not master or 2.0 + +## The actual contribution + +1. Make the changes/additions to the code, committing often and making clear what you've done +2. Make sure you write tests for your code, located in the folder structure `tests/Coduo/PHPMatcher/...` +3. Run your tests (often and while coding): `./bin/phpunit` +4. Create Pull Request on github to against proper branch diff --git a/src/Services/Telephony/Result/ExternalCallRegisterResult.php b/src/Services/Telephony/Result/ExternalCallRegisterResult.php index 26d45be7..c36fc585 100644 --- a/src/Services/Telephony/Result/ExternalCallRegisterResult.php +++ b/src/Services/Telephony/Result/ExternalCallRegisterResult.php @@ -10,12 +10,12 @@ class ExternalCallRegisterResult extends AbstractResult { /** - * @return array + * @return \Bitrix24\SDK\Services\Telephony\Result\ExternalCallRegisterItemResult * @throws \Bitrix24\SDK\Core\Exceptions\BaseException */ - - public function getExternalCallRegister(): array + public function getExternalCallRegister(): ExternalCallRegisterItemResult { - return $this->getCoreResponse()->getResponseData()->getResult()->getResultData(); + return new ExternalCallRegisterItemResult($this->getCoreResponse()->getResponseData()->getResult()->getResultData()); } + } \ No newline at end of file diff --git a/src/Services/Telephony/Service/ExternalCall.php b/src/Services/Telephony/Service/ExternalCall.php index 48874983..208535ee 100644 --- a/src/Services/Telephony/Service/ExternalCall.php +++ b/src/Services/Telephony/Service/ExternalCall.php @@ -15,19 +15,21 @@ class ExternalCall extends AbstractService{ /** * The method registers a call in Bitrix24 + * @param array{ + * userPhoneInner?: string, + * userId?: int, + * userPhoneNumber?: string, + * callStartDate?: string, + * crmCreate?: int, + * crmSource?: string, + * crmEntityType?: string, + * crmEntityId?: int, + * showCardCall?: int, + * callListId?: int, + * outsideLineNumber?: string, + * typeCall?: int, + * } $fields * - * @param string $userPhoneInner - * @param int $userId - * @param string $userPhoneNumber - * @param string $callStartDate - * @param int $crmCreate - * @param int $crmSource - * @param string $crmEntityType - * @param int $crmEntityId - * @param int $showCardCall - * @param int $callListId - * @param string $outsideLineNumber - * @param int $typeCall * * @return \Bitrix24\SDK\Services\Telephony\Result\ExternalCallRegisterResult * @throws \Bitrix24\SDK\Core\Exceptions\BaseException @@ -35,26 +37,13 @@ class ExternalCall extends AbstractService{ * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_register.php */ - public function register_call(string $userPhoneInner, int $userId, string $userPhoneNumber, string $callStartDate, int $crmCreate, int $crmSource, string $crmEntityType,int $crmEntityId, int $showCardCall,int $callListId, string $outsideLineNumber, int $typeCall): ExternalCallRegisterResult + public function registerCall(array $fields): ExternalCallRegisterResult { - return new ExternalCallRegisterResult( $this->core->call( 'telephony.externalcall.register', - [ - 'USER_PHONE_INNER'=>$userPhoneInner, - 'USER_ID'=>$userId, - 'PHONE_NUMBER'=>$userPhoneNumber, - 'CALL_START_DATE'=>$callStartDate, - 'CRM_CREATE'=>$crmCreate, - 'CRM_SOURCE'=>$crmSource, - 'USER_ENTITY_TYPE'=>$crmEntityType, - 'CRM_ENTITY_ID'=>$crmEntityId, - 'SHOW'=>$showCardCall, - 'CALL_LIST_ID'=>$callListId, - 'LINE_NUMBER'=>$outsideLineNumber, - 'TYPE'=>$typeCall, - ] + $fields, + ) ); } @@ -127,7 +116,7 @@ public function hideCallCard(string $callId, int $userId):ExternalCallHideResult * @throws \Bitrix24\SDK\Core\Exceptions\BaseException * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_finish.php */ - public function finish_call(string $callId, int $userId, int $durationCall, float $costCall, string $costCurrency, + public function finishСall(string $callId, int $userId, int $durationCall, float $costCall, string $costCurrency, string $statusCode, string $failedReason, string $recordUrlFile, int $vote, int $addMessageToChat):ExternalCallFinishResult { return new ExternalCallFinishResult( diff --git a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php index 94f83554..e0b62738 100644 --- a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php +++ b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php @@ -6,61 +6,54 @@ use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\CRM\Lead\Service\Lead; +use Bitrix24\SDK\Services\Main\Service\Main; use Bitrix24\SDK\Services\Telephony\Service\ExternalCall; use _PHPStan_59fb0a3b2\Nette\Utils\DateTime; use Bitrix24\SDK\Tests\Integration\Fabric; use DateTimeInterface; use PHPUnit\Framework\TestCase; -class ExternalCallTest extends TestCase{ +class ExternalCallTest extends TestCase +{ + protected Lead $leadService; protected ExternalCall $externalCallService; + private Main $mainService; /** * @throws BaseException * @throws TransportException * @throws \Exception - * @covers ExternalCall::register_call + * @covers ExternalCall::registerCall */ - public function testRegisterCall():void + public function testRegisterCall(): void { //Подготовка данных - - //Внутренний номер пользователя. - $userPhoneInner = '+79788045002'; - //Идентификатор пользователя. - $userId = 1; - //Номер с которого звоним. - $phoneNumber = '+79788045001'; - //Дата/время звонка - (string)$datetime = new DateTime('now'); - $callStartDate = $datetime->format(DateTimeInterface::ATOM); - //[0/1] - Автоматическое создание в CRM сущности, связанной со звонком. - $crmCreate = 1; - //1-звонок - $crmSource = 1; - //Тип объекта CRM, из карточки которого совершается звонок - /* $masType = array('CONTACT','COMPANY','LEAD'); - $randWord = array_rand($masType); - $crmEntityType = $masType[$randWord];*/ - //Не уверен, что правильно - $crmEntityType = 'COMPANY'; - $crmEntityId = 1; - //Показывать карточку или нет. - $showCard = 1; - //Идентификатор списка обзвона, к которому должен быть привязан звонок. (ГДЕ НАЙТИ СПИСОК ОБЗВОНА???) - $callListId = 1; - //Номер на который поступает звонок - $lineNumber = '+79767867656'; - /* Обязательный. Тип звонка: - 1 - исходящий - 2 - входящий - 3 - входящий с перенаправлением - 4 - обратный*/ - $typeCall = 1; - // Тест - self::assertGreaterThan(1,$this->externalCallService->register_call($userPhoneInner,$userId,$phoneNumber,$callStartDate,$crmCreate,$crmSource,$crmEntityType, - $crmEntityId,$showCard,$callListId,$lineNumber,$typeCall)->getExternalCallRegister()); + (string)$datetime = new DateTime('now'); + $callStartDate = $datetime->format(DateTimeInterface::ATOM); + $leadId = $this->leadService->add(['TITLE' => 'test lead'])->getId(); + var_dump($leadId); + $userId = $this->mainService->getCurrentUserProfile()->getUserProfile()->ID; + var_dump($userId); + $res = $this->externalCallService->registerCall([ + 'USER_PHONE_INNER' => '14', + 'user_id' => $userId, + 'PHONE_NUMBER' => '+79788045001', + 'CALL_START_DATE' => $callStartDate, + 'CRM_CREATE' => 1, + 'CRM_SOURCE' => '1', + 'CRM_ENTITY_TYPE' => 'LEAD', + 'CRM_ENTITY_ID' => $leadId, + 'SHOW' => 1, + 'CALL_LIST_ID' => 1, + 'LINE_NUMBER' => '+79767867656', + 'TYPE' => 1 + ])->getExternalCallRegister(); + var_dump($res); + //self::assertGreaterThan(1,$res); + self::assertTrue((bool)$res); + } /** @@ -69,7 +62,8 @@ public function testRegisterCall():void * @throws \Exception * @covers ExternalCall::showCallCard */ - public function testShowCallCard():void{ + public function testShowCallCard(): void + { //Внутренний номер пользователя. $userPhoneInner = '+79788045002'; //Идентификатор пользователя. @@ -80,17 +74,17 @@ public function testShowCallCard():void{ (string)$datetime = new DateTime('now'); $callStartDate = $datetime->format(DateTimeInterface::ATOM); //[0/1] - Автоматическое создание в CRM сущности, связанной со звонком. - $crmCreate = 1; + $crmCreate = 1; //1-звонок $crmSource = 1; //Тип объекта CRM, из карточки которого совершается звонок - $masType = array('CONTACT','COMPANY','LEAD'); - $randWord = array_rand($masType); + $masType = array('CONTACT', 'COMPANY', 'LEAD'); + $randWord = array_rand($masType); $crmEntityType = $masType[$randWord]; $crmEntityId = $randWord; //Не уверен, что правильно - // $crmEntityType = 'COMPANY'; - // $crmEntityId = 1; + // $crmEntityType = 'COMPANY'; + // $crmEntityId = 1; //Показывать карточку или нет. $showCard = 1; //Идентификатор списка обзвона, к которому должен быть привязан звонок. (ГДЕ НАЙТИ СПИСОК ОБЗВОНА???) @@ -104,9 +98,9 @@ public function testShowCallCard():void{ 4 - обратный*/ $typeCall = 4; - $res = []; - $res=$this->externalCallService->register_call($userPhoneInner,$userId,$phoneNumber,$callStartDate,$crmCreate,$crmSource,$crmEntityType, $crmEntityId,$showCard,$callListId,$lineNumber,$typeCall)->getExternalCallRegister(); - self::assertGreaterThan(1,$this->externalCallService->showCallCard($res['CALL_ID'],1)->getExternalCalls()); + + $res = $this->externalCallService->registerCall($userPhoneInner, $userId, $phoneNumber, $callStartDate, $crmCreate, $crmSource, $crmEntityType, $crmEntityId, $showCard, $callListId, $lineNumber, $typeCall)->getExternalCallRegister(); + self::assertGreaterThan(1, $this->externalCallService->showCallCard($res['CALL_ID'], 1)->getExternalCalls()); } /** @@ -115,7 +109,8 @@ public function testShowCallCard():void{ * @throws \Exception * @covers ExternalCall::hideCallCard */ - public function testHideCallCard():void{ + public function testHideCallCard(): void + { //Внутренний номер пользователя. $userPhoneInner = '+79788045002'; //Идентификатор пользователя. @@ -126,11 +121,11 @@ public function testHideCallCard():void{ (string)$datetime = new DateTime('now'); $callStartDate = $datetime->format(DateTimeInterface::ATOM); //[0/1] - Автоматическое создание в CRM сущности, связанной со звонком. - $crmCreate = 1; + $crmCreate = 1; //1-звонок $crmSource = 1; //Тип объекта CRM, из карточки которого совершается звонок - $masType = array('CONTACT','COMPANY','LEAD'); + $masType = array('CONTACT', 'COMPANY', 'LEAD'); $randWord = array_rand($masType); $crmEntityType = $masType[$randWord]; $crmEntityId = $randWord; @@ -151,17 +146,18 @@ public function testHideCallCard():void{ $typeCall = 4; $res = []; - $res=$this->externalCallService->register_call($userPhoneInner,$userId,$phoneNumber,$callStartDate,$crmCreate,$crmSource,$crmEntityType, $crmEntityId,$showCard,$callListId,$lineNumber,$typeCall)->getExternalCallRegister(); - self::assertGreaterThan(1,$this->externalCallService->hideCallCard($res['CALL_ID'],1)->getExternalHideCalls()); + $res = $this->externalCallService->registerCall($userPhoneInner, $userId, $phoneNumber, $callStartDate, $crmCreate, $crmSource, $crmEntityType, $crmEntityId, $showCard, $callListId, $lineNumber, $typeCall)->getExternalCallRegister(); + self::assertGreaterThan(1, $this->externalCallService->hideCallCard($res['CALL_ID'], 1)->getExternalHideCalls()); } /** * @throws TransportException * @throws BaseException * @throws \Exception - * @covers ExternalCall::finish_call + * @covers ExternalCall::finishСall */ - public function testFinishCall():void{ + public function testFinishCall(): void + { //Внутренний номер пользователя. $userPhoneInner = '+79788045002'; //Идентификатор пользователя. @@ -172,11 +168,11 @@ public function testFinishCall():void{ (string)$datetime = new DateTime('now'); $callStartDate = $datetime->format(DateTimeInterface::ATOM); //[0/1] - Автоматическое создание в CRM сущности, связанной со звонком. - $crmCreate = 1; + $crmCreate = 1; //1-звонок $crmSource = 1; //Тип объекта CRM, из карточки которого совершается звонок - $masType = array('CONTACT','COMPANY','LEAD'); + $masType = array('CONTACT', 'COMPANY', 'LEAD'); $randWord = array_rand($masType); $crmEntityType = $masType[$randWord]; $crmEntityId = $randWord; @@ -197,20 +193,20 @@ public function testFinishCall():void{ $typeCall = 2; $res = []; - $res=$this->externalCallService->register_call($userPhoneInner,$userId,$phoneNumber,$callStartDate,$crmCreate,$crmSource,$crmEntityType, $crmEntityId,$showCard,$callListId,$lineNumber,$typeCall)->getExternalCallRegister(); + $res = $this->externalCallService->registerCall($userPhoneInner, $userId, $phoneNumber, $callStartDate, $crmCreate, $crmSource, $crmEntityType, $crmEntityId, $showCard, $callListId, $lineNumber, $typeCall)->getExternalCallRegister(); //Подготовка $call_id = $res['CALL_ID']; $user_Id = 1; $duration = 255; - $cost = 5000; + $cost = 5000; $cosy_currency = 'RUB'; - $status_code = 'VI_STATUS_304'; + $status_code = 'VI_STATUS_304'; $failed_reason = ''; $record_url = ''; $vote = 5; $add_to_chat = 1; - self::assertGreaterThan(1,$this->externalCallService->finish_call($call_id,$user_Id,$duration,$cost,$cosy_currency,$status_code,$failed_reason,$record_url,$vote,$add_to_chat)->getFinishCallResult()); + self::assertGreaterThan(1, $this->externalCallService->finishСall($call_id, $user_Id, $duration, $cost, $cosy_currency, $status_code, $failed_reason, $record_url, $vote, $add_to_chat)->getFinishCallResult()); } /** @@ -219,7 +215,7 @@ public function testFinishCall():void{ * @throws \Exception * @covers ExternalCall::attachRecord */ - public function testRecordCall():void + public function testRecordCall(): void { //Внутренний номер пользователя. $userPhoneInner = '+79788045002'; @@ -231,11 +227,11 @@ public function testRecordCall():void (string)$datetime = new DateTime('now'); $callStartDate = $datetime->format(DateTimeInterface::ATOM); //[0/1] - Автоматическое создание в CRM сущности, связанной со звонком. - $crmCreate = 1; + $crmCreate = 1; //1-звонок $crmSource = 1; //Тип объекта CRM, из карточки которого совершается звонок - $masType = array('CONTACT','COMPANY','LEAD'); + $masType = array('CONTACT', 'COMPANY', 'LEAD'); $randWord = array_rand($masType); $crmEntityType = $masType[$randWord]; $crmEntityId = $randWord; @@ -256,32 +252,35 @@ public function testRecordCall():void $typeCall = 2; $res = []; - $res=$this->externalCallService->register_call($userPhoneInner,$userId,$phoneNumber,$callStartDate,$crmCreate,$crmSource,$crmEntityType, $crmEntityId,$showCard,$callListId,$lineNumber,$typeCall)->getExternalCallRegister(); + $res = $this->externalCallService->registerCall($userPhoneInner, $userId, $phoneNumber, $callStartDate, $crmCreate, $crmSource, $crmEntityType, $crmEntityId, $showCard, $callListId, $lineNumber, $typeCall)->getExternalCallRegister(); //Подготовка $call_id = $res['CALL_ID']; $user_Id = 1; $duration = 255; - $cost = 5000; + $cost = 5000; $cosy_currency = 'RUB'; - $status_code = 'VI_STATUS_304'; + $status_code = 'VI_STATUS_304'; $failed_reason = ''; $record_url = ''; $vote = 5; $add_to_chat = 1; - $this->externalCallService->finish_call($call_id,$user_Id,$duration,$cost,$cosy_currency,$status_code,$failed_reason,$record_url,$vote,$add_to_chat)->getFinishCallResult(); + $this->externalCallService->finishСall($call_id, $user_Id, $duration, $cost, $cosy_currency, $status_code, $failed_reason, $record_url, $vote, $add_to_chat)->getFinishCallResult(); $fileName = 'testFiless'; //Декодирование в base64 разобраться с этим. $content = 'filesss'; $url = 'https://vk.com/audio172690992_456241726_c88e19185934f5b9dd'; - self::assertGreaterThan(1,$this->externalCallService->attachRecord($call_id,$fileName,$content,$url)->getRecord()); + self::assertGreaterThan(1, $this->externalCallService->attachRecord($call_id, $fileName, $content, $url)->getRecord()); } + /** * @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(); } } \ No newline at end of file diff --git a/tests/Integration/Services/Telephony/Service/ExternalLineTest.php b/tests/Integration/Services/Telephony/Service/ExternalLineTest.php index 7ce7c5f7..e315d5f2 100644 --- a/tests/Integration/Services/Telephony/Service/ExternalLineTest.php +++ b/tests/Integration/Services/Telephony/Service/ExternalLineTest.php @@ -21,6 +21,8 @@ class ExternalLineTest extends TestCase { public function testAdd(): void { self::assertGreaterThan(1,$this->externalLineService->add((string)time(),sprintf('phpUnit-%s',time()))->getId()); + $res = $this->externalLineService->add((string)time(),sprintf('phpUnit-%s',time()))->getId(); + var_dump($res); } @@ -34,6 +36,8 @@ 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()); + $res = $this->externalLineService->get()->getExternalLines(); + var_dump($res); } /** From 1d2b4479ba1217b6dc28e9324d9617952f29f33d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Mon, 11 Jul 2022 19:13:18 +0300 Subject: [PATCH 363/647] =?UTF-8?q?-=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=20telephony.exter?= =?UTF-8?q?nalcall.register=20-=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D1=84=D0=B0=D0=B9=D0=BB=20CONTRIBUTING.md(=D0=BD?= =?UTF-8?q?=D0=B5=20=D1=80=D0=B5=D0=B4=D0=B0=D0=BA=D1=82=D0=B8=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BB=D1=81=D1=8F)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Result/ExternalCallRegisterItemResult.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Services/Telephony/Result/ExternalCallRegisterItemResult.php b/src/Services/Telephony/Result/ExternalCallRegisterItemResult.php index 76c4cdd9..84f82666 100644 --- a/src/Services/Telephony/Result/ExternalCallRegisterItemResult.php +++ b/src/Services/Telephony/Result/ExternalCallRegisterItemResult.php @@ -7,12 +7,12 @@ use Bitrix24\SDK\Core\Result\AbstractItem; /** - * @property-read string $callId - * @property-read int $crmCreatedLead - * @property-read int $crmEntityId - * @property-read string $crmEntityTye - * @property-read array $crmCreatedEntities - * @property-read string $leadCreationError + * @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 { From 1ea6137bef3443f9ab715a9ac0a7804849eae588 Mon Sep 17 00:00:00 2001 From: kirill Date: Tue, 12 Jul 2022 11:14:06 +0300 Subject: [PATCH 364/647] -add ExternalLine service --- .../Telephony/Service/ExternalLine.php | 19 ++---- .../Telephony/Service/ExternalLineTest.php | 65 ++++++++++--------- 2 files changed, 41 insertions(+), 43 deletions(-) diff --git a/src/Services/Telephony/Service/ExternalLine.php b/src/Services/Telephony/Service/ExternalLine.php index 9158fb58..c1427b9d 100644 --- a/src/Services/Telephony/Service/ExternalLine.php +++ b/src/Services/Telephony/Service/ExternalLine.php @@ -49,12 +49,7 @@ public function add(string $lineNumber , string $nameLine): ExternalLineAddResul public function get(): ExternalLinesResult { return new ExternalLinesResult( - $this->core->call( - 'telephony.externalLine.get', - [ - - ] - ) + $this->core->call('telephony.externalLine.get') ); } @@ -70,14 +65,14 @@ public function get(): ExternalLinesResult * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalLine_update.php */ - public function update(string $lineNumber , string $nameLine): ExternalLineUpdateResult + public function update(string $lineNumber, string $nameLine): ExternalLineUpdateResult { return new ExternalLineUpdateResult( $this->core->call('telephony.externalLine.update', - [ - 'NUMBER'=>$lineNumber, - 'NAME'=>$nameLine, - ] + [ + 'NUMBER' => $lineNumber, + 'NAME' => $nameLine, + ] ) ); } @@ -98,7 +93,7 @@ public function delete(string $lineNumber): ExternalLineDeleteResult return new ExternalLineDeleteResult( $this->core->call('telephony.externalLine.delete', [ - 'NUMBER'=>$lineNumber, + 'NUMBER' => $lineNumber, ] ) ); diff --git a/tests/Integration/Services/Telephony/Service/ExternalLineTest.php b/tests/Integration/Services/Telephony/Service/ExternalLineTest.php index e315d5f2..dfc91af9 100644 --- a/tests/Integration/Services/Telephony/Service/ExternalLineTest.php +++ b/tests/Integration/Services/Telephony/Service/ExternalLineTest.php @@ -10,7 +10,8 @@ use Bitrix24\SDK\Tests\Integration\Fabric; use PHPUnit\Framework\TestCase; -class ExternalLineTest extends TestCase { +class ExternalLineTest extends TestCase +{ protected ExternalLine $externalLineService; /** @@ -20,24 +21,19 @@ class ExternalLineTest extends TestCase { */ public function testAdd(): void { - self::assertGreaterThan(1,$this->externalLineService->add((string)time(),sprintf('phpUnit-%s',time()))->getId()); - $res = $this->externalLineService->add((string)time(),sprintf('phpUnit-%s',time()))->getId(); - var_dump($res); - + self::assertGreaterThan(1, $this->externalLineService->add((string)time(), sprintf('phpUnit-%s', time()))->getId()); } /** - * * @throws BaseException + * @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())); + $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()); - $res = $this->externalLineService->get()->getExternalLines(); - var_dump($res); } /** @@ -45,23 +41,24 @@ public function testGet(): void * @throws TransportException * @covers ExternalLine::update */ - public function testUpdateExternalLineName():void + public function testUpdateExternalLineName(): void { + $lineNumber = $this->getRandomLineNumber(); + $lineNameBefore = sprintf('phpUnit-%s-name-before', time()); - //$lineNameBefore = array((string)time() => sprintf('phpUnit-%s',time())); - $lineNumber = (string)time(); - $lineNameBefore = sprintf('phpUnit-%s',time()); + $externalLineId = $this->externalLineService->add($lineNumber, $lineNameBefore)->getId(); - self::assertGreaterThan(1,$this->externalLineService->add($lineNumber,$lineNameBefore)->getId()); - $externalLineNameBefore = array_column($this->externalLineService->get()->getExternalLines(),'NAME'); - var_dump($externalLineNameBefore); - $lineNameAfter = sprintf('phpUnit-%s-second',time()); - $this->externalLineService->update($lineNumber,$lineNameAfter)->updateExternalLineId(); - $externalLineNameAfter = array_column($this->externalLineService->get()->getExternalLines(),'NAME'); - var_dump($externalLineNameAfter); - self::assertFalse(in_array($lineNameBefore,$externalLineNameAfter),sprintf('expected update %s line name see %s name',$lineNameBefore,$lineNameAfter)); + $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)); } /** @@ -69,22 +66,20 @@ public function testUpdateExternalLineName():void * @throws TransportException * @covers ExternalLine::delete */ - public function testDelete():void + public function testDelete(): void { - $lineNumber = (string)time().(string)random_int(1,PHP_INT_MAX); + $lineNumber = $this->getRandomLineNumber(); - self::assertGreaterThan(1,$this->externalLineService->add($lineNumber,sprintf('phpUnit-%s',time()))->getId()); - $externalLineNumbersBefore = array_column($this->externalLineService->get()->getExternalLines(),'NUMBER'); + 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'); + $externalLineNumbersAfter = array_column($this->externalLineService->get()->getExternalLines(), 'NUMBER'); - $deletedLineNumber = array_values(array_diff($externalLineNumbersBefore,$externalLineNumbersAfter))[0]; - // var_dump(array_values(array_diff($externalLineNumbersBefore,$externalLineNumbersAfter))); - self::assertEquals($lineNumber,$deletedLineNumber,sprintf('expected deleted %s number see %s number',$lineNumber,$deletedLineNumber)); + $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 */ @@ -93,4 +88,12 @@ 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 From 780d38e329a7ee1636dd3cd811085719d082a7ca Mon Sep 17 00:00:00 2001 From: kirill Date: Tue, 12 Jul 2022 16:58:16 +0300 Subject: [PATCH 365/647] =?UTF-8?q?-=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D1=8B=20Ext?= =?UTF-8?q?ernalCall?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Result/ExternalCallFinishItemResult.php | 37 +++ .../Result/ExternalCallFinishResult.php | 6 +- .../Result/ExternalCallHideResult.php | 6 +- .../Result/ExternalCallRegisterResult.php | 2 +- .../Result/ExternalCallShowResult.php | 12 +- .../Telephony/Service/ExternalCall.php | 65 ++-- .../Telephony/Service/ExternalCallTest.php | 290 +++++++----------- 7 files changed, 191 insertions(+), 227 deletions(-) create mode 100644 src/Services/Telephony/Result/ExternalCallFinishItemResult.php diff --git a/src/Services/Telephony/Result/ExternalCallFinishItemResult.php b/src/Services/Telephony/Result/ExternalCallFinishItemResult.php new file mode 100644 index 00000000..d49a0e15 --- /dev/null +++ b/src/Services/Telephony/Result/ExternalCallFinishItemResult.php @@ -0,0 +1,37 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData(); + return new ExternalCallFinishItemResult($this->getCoreResponse()->getResponseData()->getResult()->getResultData()); } } \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalCallHideResult.php b/src/Services/Telephony/Result/ExternalCallHideResult.php index 1cc8fb4b..96f510cf 100644 --- a/src/Services/Telephony/Result/ExternalCallHideResult.php +++ b/src/Services/Telephony/Result/ExternalCallHideResult.php @@ -10,11 +10,11 @@ class ExternalCallHideResult extends AbstractResult { /** - * @return array + * @return bool * @throws \Bitrix24\SDK\Core\Exceptions\BaseException */ - public function getExternalHideCalls(): array + public function getExternalHideCalls(): bool { - return $this->getCoreResponse()->getResponseData()->getResult()->getResultData(); + return (bool)$this->getCoreResponse()->getResponseData()->getResult()->getResultData(); } } \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalCallRegisterResult.php b/src/Services/Telephony/Result/ExternalCallRegisterResult.php index c36fc585..4ab2b045 100644 --- a/src/Services/Telephony/Result/ExternalCallRegisterResult.php +++ b/src/Services/Telephony/Result/ExternalCallRegisterResult.php @@ -11,7 +11,7 @@ class ExternalCallRegisterResult extends AbstractResult { /** * @return \Bitrix24\SDK\Services\Telephony\Result\ExternalCallRegisterItemResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws BaseException */ public function getExternalCallRegister(): ExternalCallRegisterItemResult { diff --git a/src/Services/Telephony/Result/ExternalCallShowResult.php b/src/Services/Telephony/Result/ExternalCallShowResult.php index 2ef78a66..d0ddf3e9 100644 --- a/src/Services/Telephony/Result/ExternalCallShowResult.php +++ b/src/Services/Telephony/Result/ExternalCallShowResult.php @@ -9,12 +9,14 @@ class ExternalCallShowResult extends AbstractResult { + /* /** - * @return array - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @return bool + * @throws BaseException */ - public function getExternalCalls(): array + /* + public function getExternalCalls(): bool { - return $this->getCoreResponse()->getResponseData()->getResult()->getResultData(); - } + return (bool)$this->getCoreResponse()->getResponseData()->getResult()->getResultData(); + }*/ } \ No newline at end of file diff --git a/src/Services/Telephony/Service/ExternalCall.php b/src/Services/Telephony/Service/ExternalCall.php index 208535ee..bc17b264 100644 --- a/src/Services/Telephony/Service/ExternalCall.php +++ b/src/Services/Telephony/Service/ExternalCall.php @@ -15,19 +15,20 @@ class ExternalCall extends AbstractService{ /** * The method registers a call in Bitrix24 + * * @param array{ - * userPhoneInner?: string, - * userId?: int, - * userPhoneNumber?: string, - * callStartDate?: string, - * crmCreate?: int, - * crmSource?: string, - * crmEntityType?: string, - * crmEntityId?: int, - * showCardCall?: int, - * callListId?: int, - * outsideLineNumber?: string, - * typeCall?: int, + * 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 * * @@ -43,7 +44,6 @@ public function registerCall(array $fields): ExternalCallRegisterResult $this->core->call( 'telephony.externalcall.register', $fields, - ) ); } @@ -100,40 +100,31 @@ public function hideCallCard(string $callId, int $userId):ExternalCallHideResult /** * Method completes the call, registers it in the statistics and hides the call ID screen from the user. - * @param string $callId - * @param int $userId - * @param int $durationCall - * @param float $costCall - * @param string $costCurrency - * @param string $statusCode - * @param string $failedReason - * @param string $recordUrlFile - * @param int $vote - * @param int $addMessageToChat + * + * @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Сall(string $callId, int $userId, int $durationCall, float $costCall, string $costCurrency, - string $statusCode, string $failedReason, string $recordUrlFile, int $vote, int $addMessageToChat):ExternalCallFinishResult + public function finishCall(array $fields):ExternalCallFinishResult { return new ExternalCallFinishResult( $this->core->call( 'telephony.externalcall.finish', - [ - 'CALL_ID'=>$callId, - 'USER_ID'=>$userId, - 'DURATION'=>$durationCall, - 'COST'=>$costCall, - 'COST_CURRENCY'=>$costCurrency, - 'STATUS_CODE'=>$statusCode, - 'FAILED_REASON'=>$failedReason, - 'RECORD_URL'=>$recordUrlFile, - 'VOTE'=>$vote, - 'ADD_TO_CHAT'=>$addMessageToChat, - ] + $fields ) ); } diff --git a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php index e0b62738..6d42368f 100644 --- a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php +++ b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php @@ -12,6 +12,7 @@ use _PHPStan_59fb0a3b2\Nette\Utils\DateTime; use Bitrix24\SDK\Tests\Integration\Fabric; use DateTimeInterface; +use Exception; use PHPUnit\Framework\TestCase; class ExternalCallTest extends TestCase @@ -23,7 +24,7 @@ class ExternalCallTest extends TestCase /** * @throws BaseException * @throws TransportException - * @throws \Exception + * @throws Exception * @covers ExternalCall::registerCall */ public function testRegisterCall(): void @@ -33,12 +34,10 @@ public function testRegisterCall(): void (string)$datetime = new DateTime('now'); $callStartDate = $datetime->format(DateTimeInterface::ATOM); $leadId = $this->leadService->add(['TITLE' => 'test lead'])->getId(); - var_dump($leadId); $userId = $this->mainService->getCurrentUserProfile()->getUserProfile()->ID; - var_dump($userId); - $res = $this->externalCallService->registerCall([ + $res = $this->externalCallService->registerCall([ 'USER_PHONE_INNER' => '14', - 'user_id' => $userId, + 'USER_ID' => $userId, 'PHONE_NUMBER' => '+79788045001', 'CALL_START_DATE' => $callStartDate, 'CRM_CREATE' => 1, @@ -48,10 +47,10 @@ public function testRegisterCall(): void 'SHOW' => 1, 'CALL_LIST_ID' => 1, 'LINE_NUMBER' => '+79767867656', - 'TYPE' => 1 + 'TYPE' => 1, ])->getExternalCallRegister(); var_dump($res); - //self::assertGreaterThan(1,$res); + self::assertGreaterThan(1,$res); self::assertTrue((bool)$res); } @@ -59,219 +58,154 @@ public function testRegisterCall(): void /** * @throws BaseException * @throws TransportException - * @throws \Exception + * @throws Exception * @covers ExternalCall::showCallCard */ public function testShowCallCard(): void { - //Внутренний номер пользователя. - $userPhoneInner = '+79788045002'; - //Идентификатор пользователя. - $userId = 1; - //Номер с которого звоним. - $phoneNumber = '+79788045001'; - //Дата/время звонка (string)$datetime = new DateTime('now'); $callStartDate = $datetime->format(DateTimeInterface::ATOM); - //[0/1] - Автоматическое создание в CRM сущности, связанной со звонком. - $crmCreate = 1; - //1-звонок - $crmSource = 1; - //Тип объекта CRM, из карточки которого совершается звонок - $masType = array('CONTACT', 'COMPANY', 'LEAD'); - $randWord = array_rand($masType); - $crmEntityType = $masType[$randWord]; - $crmEntityId = $randWord; - //Не уверен, что правильно - // $crmEntityType = 'COMPANY'; - // $crmEntityId = 1; - //Показывать карточку или нет. - $showCard = 1; - //Идентификатор списка обзвона, к которому должен быть привязан звонок. (ГДЕ НАЙТИ СПИСОК ОБЗВОНА???) - $callListId = 1; - //Номер на который поступает звонок - $lineNumber = '+79767867658'; - /* Обязательный. Тип звонка: - 1 - исходящий - 2 - входящий - 3 - входящий с перенаправлением - 4 - обратный*/ - $typeCall = 4; - - - $res = $this->externalCallService->registerCall($userPhoneInner, $userId, $phoneNumber, $callStartDate, $crmCreate, $crmSource, $crmEntityType, $crmEntityId, $showCard, $callListId, $lineNumber, $typeCall)->getExternalCallRegister(); - self::assertGreaterThan(1, $this->externalCallService->showCallCard($res['CALL_ID'], 1)->getExternalCalls()); + $leadId = $this->leadService->add(['TITLE' => 'test lead'])->getId(); + $userId = $this->mainService->getCurrentUserProfile()->getUserProfile()->ID; + $res = $this->externalCallService->registerCall([ + 'USER_PHONE_INNER' => '14', + 'USER_ID' => $userId, + 'PHONE_NUMBER' => '+79788045001', + 'CALL_START_DATE' => $callStartDate, + 'CRM_CREATE' => 1, + 'CRM_SOURCE' => '1', + 'CRM_ENTITY_TYPE' => 'LEAD', + 'CRM_ENTITY_ID' => $leadId, + 'SHOW' => 1, + 'CALL_LIST_ID' => 1, + 'LINE_NUMBER' => '+79767867656', + 'TYPE' => 1 + ])->getExternalCallRegister()->CALL_ID; + $newRes = $this->externalCallService->showCallCard($res, 1); + var_dump($newRes); + self::assertGreaterThan(1,$this->externalCallService->showCallCard($res, 1)); } /** * @throws BaseException * @throws TransportException - * @throws \Exception + * @throws Exception * @covers ExternalCall::hideCallCard */ public function testHideCallCard(): void { - //Внутренний номер пользователя. - $userPhoneInner = '+79788045002'; - //Идентификатор пользователя. - $userId = 1; - //Номер с которого звоним. - $phoneNumber = '+79788045001'; - //Дата/время звонка (string)$datetime = new DateTime('now'); $callStartDate = $datetime->format(DateTimeInterface::ATOM); - //[0/1] - Автоматическое создание в CRM сущности, связанной со звонком. - $crmCreate = 1; - //1-звонок - $crmSource = 1; - //Тип объекта CRM, из карточки которого совершается звонок - $masType = array('CONTACT', 'COMPANY', 'LEAD'); - $randWord = array_rand($masType); - $crmEntityType = $masType[$randWord]; - $crmEntityId = $randWord; - //Не уверен, что правильно - // $crmEntityType = 'COMPANY'; - // $crmEntityId = 1; - //Показывать карточку или нет. - $showCard = 1; - //Идентификатор списка обзвона, к которому должен быть привязан звонок. (ГДЕ НАЙТИ СПИСОК ОБЗВОНА???) - $callListId = 1; - //Номер на который поступает звонок - $lineNumber = '+79767867658'; - /* Обязательный. Тип звонка: - 1 - исходящий - 2 - входящий - 3 - входящий с перенаправлением - 4 - обратный*/ - $typeCall = 4; - - $res = []; - $res = $this->externalCallService->registerCall($userPhoneInner, $userId, $phoneNumber, $callStartDate, $crmCreate, $crmSource, $crmEntityType, $crmEntityId, $showCard, $callListId, $lineNumber, $typeCall)->getExternalCallRegister(); - self::assertGreaterThan(1, $this->externalCallService->hideCallCard($res['CALL_ID'], 1)->getExternalHideCalls()); + $leadId = $this->leadService->add(['TITLE' => 'test lead'])->getId(); + $userId = $this->mainService->getCurrentUserProfile()->getUserProfile()->ID; + $res = $this->externalCallService->registerCall([ + 'USER_PHONE_INNER' => '14', + 'user_id' => $userId, + 'PHONE_NUMBER' => '+79788045001', + 'CALL_START_DATE' => $callStartDate, + 'CRM_CREATE' => 1, + 'CRM_SOURCE' => '1', + 'CRM_ENTITY_TYPE' => 'LEAD', + 'CRM_ENTITY_ID' => $leadId, + 'SHOW' => 1, + 'CALL_LIST_ID' => 1, + 'LINE_NUMBER' => '+79767867656', + 'TYPE' => 1 + ])->getExternalCallRegister()->CALL_ID; + $newRes = $this->externalCallService->hideCallCard($res, 1)->getExternalHideCalls(); + var_dump($newRes); + self::assertTrue($this->externalCallService->hideCallCard($res, 1)->getExternalHideCalls()); } /** * @throws TransportException * @throws BaseException - * @throws \Exception + * @throws Exception * @covers ExternalCall::finishСall */ public function testFinishCall(): void { - //Внутренний номер пользователя. - $userPhoneInner = '+79788045002'; - //Идентификатор пользователя. - $userId = 1; - //Номер с которого звоним. - $phoneNumber = '+79788045001'; - //Дата/время звонка (string)$datetime = new DateTime('now'); $callStartDate = $datetime->format(DateTimeInterface::ATOM); - //[0/1] - Автоматическое создание в CRM сущности, связанной со звонком. - $crmCreate = 1; - //1-звонок - $crmSource = 1; - //Тип объекта CRM, из карточки которого совершается звонок - $masType = array('CONTACT', 'COMPANY', 'LEAD'); - $randWord = array_rand($masType); - $crmEntityType = $masType[$randWord]; - $crmEntityId = $randWord; - //Не уверен, что правильно - // $crmEntityType = 'COMPANY'; - // $crmEntityId = 1; - //Показывать карточку или нет. - $showCard = 1; - //Идентификатор списка обзвона, к которому должен быть привязан звонок. (ГДЕ НАЙТИ СПИСОК ОБЗВОНА???) - $callListId = 1; - //Номер на который поступает звонок - $lineNumber = '+79767867658'; - /* Обязательный. Тип звонка: - 1 - исходящий - 2 - входящий - 3 - входящий с перенаправлением - 4 - обратный*/ - $typeCall = 2; - - $res = []; - $res = $this->externalCallService->registerCall($userPhoneInner, $userId, $phoneNumber, $callStartDate, $crmCreate, $crmSource, $crmEntityType, $crmEntityId, $showCard, $callListId, $lineNumber, $typeCall)->getExternalCallRegister(); + $leadId = $this->leadService->add(['TITLE' => 'test lead'])->getId(); + $userId = $this->mainService->getCurrentUserProfile()->getUserProfile()->ID; + $res = $this->externalCallService->registerCall([ + 'USER_PHONE_INNER' => '14', + 'user_id' => $userId, + 'PHONE_NUMBER' => '+79788045001', + 'CALL_START_DATE' => $callStartDate, + 'CRM_CREATE' => 1, + 'CRM_SOURCE' => '1', + 'CRM_ENTITY_TYPE' => 'LEAD', + 'CRM_ENTITY_ID' => $leadId, + 'SHOW' => 1, + 'CALL_LIST_ID' => 1, + 'LINE_NUMBER' => '+79767867656', + 'TYPE' => 1 + ])->getExternalCallRegister(); - //Подготовка - $call_id = $res['CALL_ID']; - $user_Id = 1; - $duration = 255; - $cost = 5000; - $cosy_currency = 'RUB'; - $status_code = 'VI_STATUS_304'; - $failed_reason = ''; - $record_url = ''; - $vote = 5; - $add_to_chat = 1; - self::assertGreaterThan(1, $this->externalCallService->finishСall($call_id, $user_Id, $duration, $cost, $cosy_currency, $status_code, $failed_reason, $record_url, $vote, $add_to_chat)->getFinishCallResult()); + $newRes = $this->externalCallService->finishCall([ + 'CALL_ID'=>$res->CALL_ID, + 'USER_ID'=>$userId, + 'DURATION'=>255, + 'COST'=>5000, + 'COST_CURRENCY'=>'RUB', + 'STATUS_CODE'=>'VI_STATUS_304', + 'FAILED_REASON'=>'', + 'RECORD_URL'=>'', + 'VOTE'=>5, + 'ADD_TO_CHAT'=>1 + ])->getExternalCallFinish(); + var_dump($newRes); + self::assertTrue((bool)$newRes); + self::assertContains($res->CALL_ID,$newRes); } /** * @throws TransportException * @throws BaseException - * @throws \Exception + * @throws Exception * @covers ExternalCall::attachRecord */ public function testRecordCall(): void { - //Внутренний номер пользователя. - $userPhoneInner = '+79788045002'; - //Идентификатор пользователя. - $userId = 1; - //Номер с которого звоним. - $phoneNumber = '+79788045001'; - //Дата/время звонка (string)$datetime = new DateTime('now'); $callStartDate = $datetime->format(DateTimeInterface::ATOM); - //[0/1] - Автоматическое создание в CRM сущности, связанной со звонком. - $crmCreate = 1; - //1-звонок - $crmSource = 1; - //Тип объекта CRM, из карточки которого совершается звонок - $masType = array('CONTACT', 'COMPANY', 'LEAD'); - $randWord = array_rand($masType); - $crmEntityType = $masType[$randWord]; - $crmEntityId = $randWord; - //Не уверен, что правильно - // $crmEntityType = 'COMPANY'; - // $crmEntityId = 1; - //Показывать карточку или нет. - $showCard = 1; - //Идентификатор списка обзвона, к которому должен быть привязан звонок. (ГДЕ НАЙТИ СПИСОК ОБЗВОНА???) - $callListId = 1; - //Номер на который поступает звонок - $lineNumber = '+79767867658'; - /* Обязательный. Тип звонка: - 1 - исходящий - 2 - входящий - 3 - входящий с перенаправлением - 4 - обратный*/ - $typeCall = 2; - - $res = []; - $res = $this->externalCallService->registerCall($userPhoneInner, $userId, $phoneNumber, $callStartDate, $crmCreate, $crmSource, $crmEntityType, $crmEntityId, $showCard, $callListId, $lineNumber, $typeCall)->getExternalCallRegister(); - - //Подготовка - $call_id = $res['CALL_ID']; - $user_Id = 1; - $duration = 255; - $cost = 5000; - $cosy_currency = 'RUB'; - $status_code = 'VI_STATUS_304'; - $failed_reason = ''; - $record_url = ''; - $vote = 5; - $add_to_chat = 1; - $this->externalCallService->finishСall($call_id, $user_Id, $duration, $cost, $cosy_currency, $status_code, $failed_reason, $record_url, $vote, $add_to_chat)->getFinishCallResult(); - - $fileName = 'testFiless'; + $leadId = $this->leadService->add(['TITLE' => 'test lead'])->getId(); + $userId = $this->mainService->getCurrentUserProfile()->getUserProfile()->ID; + $res = $this->externalCallService->registerCall([ + 'USER_PHONE_INNER' => '14', + 'user_id' => $userId, + 'PHONE_NUMBER' => '+79788045001', + 'CALL_START_DATE' => $callStartDate, + 'CRM_CREATE' => 1, + 'CRM_SOURCE' => '1', + 'CRM_ENTITY_TYPE' => 'LEAD', + 'CRM_ENTITY_ID' => $leadId, + 'SHOW' => 1, + 'CALL_LIST_ID' => 1, + 'LINE_NUMBER' => '+79767867656', + 'TYPE' => 1 + ])->getExternalCallRegister()->CALL_ID; + + $newRes = $this->externalCallService->finishCall([ + 'CALL_ID'=>$res, + 'USER_ID'=>$userId, + 'DURATION'=>255, + 'COST'=>5000, + 'COST_CURRENCY'=>'RUB', + 'STATUS_CODE'=>'VI_STATUS_304', + 'FAILED_REASON'=>'', + 'RECORD_URL'=>'', + 'VOTE'=>5, + 'ADD_TO_CHAT'=>1 + ])->getExternalCallFinish(); + + $fileName = sprintf('test%s', time()); //Декодирование в base64 разобраться с этим. $content = 'filesss'; - $url = 'https://vk.com/audio172690992_456241726_c88e19185934f5b9dd'; - self::assertGreaterThan(1, $this->externalCallService->attachRecord($call_id, $fileName, $content, $url)->getRecord()); + $url = 'https://vk.com/audio172690992_456241640_4836017d770715b9af'; + self::assertGreaterThan(1, $this->externalCallService->attachRecord($res, $fileName, $content, $url)->getRecord()); } /** From 35e93818a3981f869e9e93b9cbb2a159dce469f5 Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 13 Jul 2022 00:16:47 +0300 Subject: [PATCH 366/647] add Event handlers service Signed-off-by: mesilov --- CHANGELOG.md | 7 +- src/Services/Main/MainServiceBuilder.php | 13 ++ .../Main/Result/EventHandlerBindResult.php | 20 +++ .../Main/Result/EventHandlerItemResult.php | 17 +++ .../Main/Result/EventHandlerUnbindResult.php | 20 +++ .../Main/Result/EventHandlersResult.php | 25 ++++ src/Services/Main/Result/EventListResult.php | 20 +++ src/Services/Main/Service/Event.php | 119 ++++++++++++++++++ 8 files changed, 238 insertions(+), 3 deletions(-) create mode 100644 src/Services/Main/Result/EventHandlerBindResult.php create mode 100644 src/Services/Main/Result/EventHandlerItemResult.php create mode 100644 src/Services/Main/Result/EventHandlerUnbindResult.php create mode 100644 src/Services/Main/Result/EventHandlersResult.php create mode 100644 src/Services/Main/Result/EventListResult.php create mode 100644 src/Services/Main/Service/Event.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 47029535..49566977 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,14 @@ # bitrix24-php-sdk change log -## 2.0-alpha.7 — 13.06.2022 +## 2.0-alpha.7 — 15.07.2022 ### Added * add new scope `UserConsent` and services [add UserConsent support](https://github.com/mesilov/bitrix24-php-sdk/issues/285) * add new scope `Placements` and services [add Placements support](https://github.com/mesilov/bitrix24-php-sdk/issues/274) -* add new service `Leads` in scope «CRM» [add Leads support](https://github.com/mesilov/bitrix24-php-sdk/issues/282) -* add new service `Activity` in scope «CRM» [add Activity support](https://github.com/mesilov/bitrix24-php-sdk/issues/283) +* add in scope `CRM` new service `Leads` in scope «CRM» [add Leads support](https://github.com/mesilov/bitrix24-php-sdk/issues/282) +* add in scope `CRM` new service `Activity` in scope «CRM» [add Activity support](https://github.com/mesilov/bitrix24-php-sdk/issues/283) +* add in scope «Main» new service `Events` [add incoming events support](https://github.com/mesilov/bitrix24-php-sdk/issues/296) * add support Application level events: `ONAPPINSTALL` and `ONAPPUNINSTALL` [add incoming events support](https://github.com/mesilov/bitrix24-php-sdk/issues/296) * add method `Core\Batch::updateEntityItems` for [update items in batch mode](https://github.com/mesilov/bitrix24-php-sdk/issues/268) and diff --git a/src/Services/Main/MainServiceBuilder.php b/src/Services/Main/MainServiceBuilder.php index 9591f032..ce6f34ce 100644 --- a/src/Services/Main/MainServiceBuilder.php +++ b/src/Services/Main/MainServiceBuilder.php @@ -6,6 +6,7 @@ use Bitrix24\SDK\Services\AbstractServiceBuilder; use Bitrix24\SDK\Services\Main\Service\Main; +use Bitrix24\SDK\Services\Main\Service\Event; /** * Class MainServiceBuilder @@ -25,4 +26,16 @@ public function main(): Main return $this->serviceCache[__METHOD__]; } + + /** + * @return Event + */ + public function event(): Event + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Event($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } } \ No newline at end of file diff --git a/src/Services/Main/Result/EventHandlerBindResult.php b/src/Services/Main/Result/EventHandlerBindResult.php new file mode 100644 index 00000000..44ef622d --- /dev/null +++ b/src/Services/Main/Result/EventHandlerBindResult.php @@ -0,0 +1,20 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Main/Result/EventHandlerItemResult.php b/src/Services/Main/Result/EventHandlerItemResult.php new file mode 100644 index 00000000..75c0a8c6 --- /dev/null +++ b/src/Services/Main/Result/EventHandlerItemResult.php @@ -0,0 +1,17 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData()['count']; + } +} \ No newline at end of file diff --git a/src/Services/Main/Result/EventHandlersResult.php b/src/Services/Main/Result/EventHandlersResult.php new file mode 100644 index 00000000..990aab49 --- /dev/null +++ b/src/Services/Main/Result/EventHandlersResult.php @@ -0,0 +1,25 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData() as $event) { + $res[] = new EventHandlerItemResult($event); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/Main/Result/EventListResult.php b/src/Services/Main/Result/EventListResult.php new file mode 100644 index 00000000..36bc8b78 --- /dev/null +++ b/src/Services/Main/Result/EventListResult.php @@ -0,0 +1,20 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData(); + } +} \ No newline at end of file diff --git a/src/Services/Main/Service/Event.php b/src/Services/Main/Service/Event.php new file mode 100644 index 00000000..cf5d2fa6 --- /dev/null +++ b/src/Services/Main/Service/Event.php @@ -0,0 +1,119 @@ +core->call( + 'events', + $scopeCode !== null ? ['scope' => (new Scope([$scopeCode]))->getScopeCodes()[0]] : [] + ) + ); + } + + /** + * Installs a new event handler. + * + * @param string $eventCode + * @param string $handlerUrl + * @param int|null $userId + * @param array|null $options + * + * @return \Bitrix24\SDK\Services\Main\Result\EventHandlerBindResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/general/events_method/event_bind.php + */ + public function bind(string $eventCode, string $handlerUrl, ?int $userId = null, ?array $options = null): EventHandlerBindResult + { + $params = [ + 'event' => $eventCode, + 'handler' => $handlerUrl, + 'event_type ' => 'online', + ]; + if ($userId !== null) { + $params['auth_type'] = $userId; + } + if (is_array($options)) { + $params = array_merge($params, $options); + } + + return new EventHandlerBindResult($this->core->call('event.bind', $params)); + } + + /** + * Uninstalls a previously installed event handler. + * + * @param string $eventCode + * @param string $handlerUrl + * @param int|null $userId + * + * @return \Bitrix24\SDK\Services\Main\Result\EventHandlerUnbindResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/general/events_method/event_unbind.php + */ + public function unbind(string $eventCode, string $handlerUrl, ?int $userId = null): EventHandlerUnbindResult + { + $params = [ + 'event' => $eventCode, + 'handler' => $handlerUrl, + 'event_type ' => 'online', + ]; + if ($userId !== null) { + $params['auth_type'] = $userId; + } + + return new EventHandlerUnbindResult($this->core->call('event.unbind', $params)); + } + + /** + * @param array $payload + * + * @return \Bitrix24\SDK\Core\Response\Response + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/rest_sum/test_handler.php + */ + public function test(array $payload = []): Response + { + return $this->core->call('event.test', $payload); + } + + /** + * Obtaining a list of registered event handlers. + * + * @return \Bitrix24\SDK\Services\Main\Result\EventHandlersResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/general/events_method/event_get.php + */ + public function get(): EventHandlersResult + { + return new EventHandlersResult($this->core->call('event.get')); + } +} \ No newline at end of file From 166ec1584002b1d154184cc11ffd985421e35602 Mon Sep 17 00:00:00 2001 From: kirill Date: Wed, 13 Jul 2022 14:04:26 +0300 Subject: [PATCH 367/647] -fix type casting --- src/Services/Main/Result/UserProfileItemResult.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Services/Main/Result/UserProfileItemResult.php b/src/Services/Main/Result/UserProfileItemResult.php index 433a5003..d5bc4938 100644 --- a/src/Services/Main/Result/UserProfileItemResult.php +++ b/src/Services/Main/Result/UserProfileItemResult.php @@ -22,6 +22,19 @@ */ class UserProfileItemResult extends AbstractItem { + public function __get($offset) + { + switch ($offset) { + case 'ID': + if ($this->data[$offset] !== '' && $this->data[$offset] !== null) { + return (int)$this->data[$offset]; + } + return null; + default: + return parent::__get($offset); + } + } + /** * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException */ From e7acd90ba3f59c9e495814850c3fd90a0cfbadac Mon Sep 17 00:00:00 2001 From: kirill Date: Wed, 13 Jul 2022 14:43:55 +0300 Subject: [PATCH 368/647] -update ExternalCall service. --- .../Result/ExternalCallHideResult.php | 6 +- .../Result/ExternalCallRecordResult.php | 6 +- .../Result/ExternalCallShowResult.php | 13 +- .../Telephony/Service/ExternalCall.php | 8 +- .../Telephony/Service/ExternalCallTest.php | 231 +++++++++++------- 5 files changed, 165 insertions(+), 99 deletions(-) diff --git a/src/Services/Telephony/Result/ExternalCallHideResult.php b/src/Services/Telephony/Result/ExternalCallHideResult.php index 96f510cf..102b72a5 100644 --- a/src/Services/Telephony/Result/ExternalCallHideResult.php +++ b/src/Services/Telephony/Result/ExternalCallHideResult.php @@ -9,12 +9,14 @@ class ExternalCallHideResult extends AbstractResult { + /** * @return bool * @throws \Bitrix24\SDK\Core\Exceptions\BaseException */ - public function getExternalHideCalls(): bool + + public function isHided(): bool { - return (bool)$this->getCoreResponse()->getResponseData()->getResult()->getResultData(); + return $this->getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; } } \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalCallRecordResult.php b/src/Services/Telephony/Result/ExternalCallRecordResult.php index cb44487e..d059d448 100644 --- a/src/Services/Telephony/Result/ExternalCallRecordResult.php +++ b/src/Services/Telephony/Result/ExternalCallRecordResult.php @@ -9,11 +9,11 @@ class ExternalCallRecordResult extends AbstractResult { /** - * @return array + * @return int * @throws \Bitrix24\SDK\Core\Exceptions\BaseException */ - public function getRecord():array + public function getFileId():int { - return $this->getCoreResponse()->getResponseData()->getResult()->getResultData(); + return $this->getCoreResponse()->getResponseData()->getResult()->getResultData()['FILE_ID']; } } \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalCallShowResult.php b/src/Services/Telephony/Result/ExternalCallShowResult.php index d0ddf3e9..a8aa1fd3 100644 --- a/src/Services/Telephony/Result/ExternalCallShowResult.php +++ b/src/Services/Telephony/Result/ExternalCallShowResult.php @@ -4,19 +4,22 @@ 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 getExternalCalls(): bool + + public function isShown(): bool { - return (bool)$this->getCoreResponse()->getResponseData()->getResult()->getResultData(); - }*/ + return $this->getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + } + + } \ No newline at end of file diff --git a/src/Services/Telephony/Service/ExternalCall.php b/src/Services/Telephony/Service/ExternalCall.php index bc17b264..0d90ba33 100644 --- a/src/Services/Telephony/Service/ExternalCall.php +++ b/src/Services/Telephony/Service/ExternalCall.php @@ -61,7 +61,7 @@ public function registerCall(array $fields): ExternalCallRegisterResult * @throws \Bitrix24\SDK\Core\Exceptions\TransportException * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_show.php */ - public function showCallCard(string $callId, int $userId):ExternalCallShowResult{ + public function show(string $callId, int $userId):ExternalCallShowResult{ return new ExternalCallShowResult( $this->core->call( 'telephony.externalcall.show', @@ -86,7 +86,7 @@ public function showCallCard(string $callId, int $userId):ExternalCallShowResult * @throws \Bitrix24\SDK\Core\Exceptions\BaseException * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_hide.php */ - public function hideCallCard(string $callId, int $userId):ExternalCallHideResult{ + public function hide(string $callId, int $userId):ExternalCallHideResult{ return new ExternalCallHideResult( $this->core->call( 'telephony.externalcall.hide', @@ -119,7 +119,7 @@ public function hideCallCard(string $callId, int $userId):ExternalCallHideResult * @throws \Bitrix24\SDK\Core\Exceptions\BaseException * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_finish.php */ - public function finishCall(array $fields):ExternalCallFinishResult + public function finish(array $fields):ExternalCallFinishResult { return new ExternalCallFinishResult( $this->core->call( @@ -142,7 +142,7 @@ public function finishCall(array $fields):ExternalCallFinishResult * @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):ExternalCallRecordResult + public function attachRecord(string $callId, string $fileName, string $fileContent,?string $recordUrl = null):ExternalCallRecordResult { return new ExternalCallRecordResult( $this->core->call( diff --git a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php index 6d42368f..c93205ad 100644 --- a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php +++ b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php @@ -31,27 +31,40 @@ public function testRegisterCall(): void { //Подготовка данных // Тест - (string)$datetime = new DateTime('now'); - $callStartDate = $datetime->format(DateTimeInterface::ATOM); - $leadId = $this->leadService->add(['TITLE' => 'test lead'])->getId(); - $userId = $this->mainService->getCurrentUserProfile()->getUserProfile()->ID; - $res = $this->externalCallService->registerCall([ + (string)$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' => '+79788045001', + 'PHONE_NUMBER' => $phoneNumber, 'CALL_START_DATE' => $callStartDate, - 'CRM_CREATE' => 1, + 'CRM_CREATE' => 0, 'CRM_SOURCE' => '1', 'CRM_ENTITY_TYPE' => 'LEAD', 'CRM_ENTITY_ID' => $leadId, 'SHOW' => 1, 'CALL_LIST_ID' => 1, - 'LINE_NUMBER' => '+79767867656', + 'LINE_NUMBER' => $phoneNumber, 'TYPE' => 1, ])->getExternalCallRegister(); - var_dump($res); - self::assertGreaterThan(1,$res); - self::assertTrue((bool)$res); + + 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)); + } @@ -59,106 +72,143 @@ public function testRegisterCall(): void * @throws BaseException * @throws TransportException * @throws Exception - * @covers ExternalCall::showCallCard + * @covers ExternalCall::show */ public function testShowCallCard(): void { (string)$datetime = new DateTime('now'); $callStartDate = $datetime->format(DateTimeInterface::ATOM); - $leadId = $this->leadService->add(['TITLE' => 'test lead'])->getId(); + $phoneNumber = '+79788045001'; + $leadId = $this->leadService->add( + [ + 'TITLE' => 'test lead', + 'PHONE' => [ + [ + 'VALUE' => $phoneNumber, + 'VALUE_TYPE' => 'WORK' + ] + ] + ] + )->getId(); $userId = $this->mainService->getCurrentUserProfile()->getUserProfile()->ID; - $res = $this->externalCallService->registerCall([ + $registerCallResult = $this->externalCallService->registerCall([ 'USER_PHONE_INNER' => '14', 'USER_ID' => $userId, - 'PHONE_NUMBER' => '+79788045001', + 'PHONE_NUMBER' => $phoneNumber, 'CALL_START_DATE' => $callStartDate, - 'CRM_CREATE' => 1, + 'CRM_CREATE' => 0, 'CRM_SOURCE' => '1', 'CRM_ENTITY_TYPE' => 'LEAD', 'CRM_ENTITY_ID' => $leadId, - 'SHOW' => 1, + 'SHOW' => 0, 'CALL_LIST_ID' => 1, - 'LINE_NUMBER' => '+79767867656', - 'TYPE' => 1 - ])->getExternalCallRegister()->CALL_ID; - $newRes = $this->externalCallService->showCallCard($res, 1); - var_dump($newRes); - self::assertGreaterThan(1,$this->externalCallService->showCallCard($res, 1)); + 'LINE_NUMBER' => $phoneNumber, + 'TYPE' => 1, + ])->getExternalCallRegister(); + self::assertTrue($this->externalCallService->show($registerCallResult->CALL_ID,$userId )->isShown()); } /** * @throws BaseException * @throws TransportException * @throws Exception - * @covers ExternalCall::hideCallCard + * @covers ExternalCall::hide */ public function testHideCallCard(): void { (string)$datetime = new DateTime('now'); $callStartDate = $datetime->format(DateTimeInterface::ATOM); - $leadId = $this->leadService->add(['TITLE' => 'test lead'])->getId(); + $phoneNumber = '+79788045001'; + $leadId = $this->leadService->add( + [ + 'TITLE' => 'test lead', + 'PHONE' => [ + [ + 'VALUE' => $phoneNumber, + 'VALUE_TYPE' => 'WORK' + ] + ] + ] + )->getId(); $userId = $this->mainService->getCurrentUserProfile()->getUserProfile()->ID; - $res = $this->externalCallService->registerCall([ + $registerCallResult = $this->externalCallService->registerCall([ 'USER_PHONE_INNER' => '14', - 'user_id' => $userId, - 'PHONE_NUMBER' => '+79788045001', + 'USER_ID' => $userId, + 'PHONE_NUMBER' => $phoneNumber, 'CALL_START_DATE' => $callStartDate, - 'CRM_CREATE' => 1, + 'CRM_CREATE' => 0, 'CRM_SOURCE' => '1', 'CRM_ENTITY_TYPE' => 'LEAD', 'CRM_ENTITY_ID' => $leadId, - 'SHOW' => 1, + 'SHOW' => 0, 'CALL_LIST_ID' => 1, - 'LINE_NUMBER' => '+79767867656', - 'TYPE' => 1 - ])->getExternalCallRegister()->CALL_ID; - $newRes = $this->externalCallService->hideCallCard($res, 1)->getExternalHideCalls(); - var_dump($newRes); - self::assertTrue($this->externalCallService->hideCallCard($res, 1)->getExternalHideCalls()); + 'LINE_NUMBER' => $phoneNumber, + 'TYPE' => 1, + ])->getExternalCallRegister(); + self::assertTrue($this->externalCallService->hide($registerCallResult->CALL_ID, $userId)->isHided()); } /** * @throws TransportException * @throws BaseException * @throws Exception - * @covers ExternalCall::finishСall + * @covers ExternalCall::finish */ - public function testFinishCall(): void + public function testFinish(): void { (string)$datetime = new DateTime('now'); $callStartDate = $datetime->format(DateTimeInterface::ATOM); - $leadId = $this->leadService->add(['TITLE' => 'test lead'])->getId(); + $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; - $res = $this->externalCallService->registerCall([ + $registerCallResult = $this->externalCallService->registerCall([ 'USER_PHONE_INNER' => '14', - 'user_id' => $userId, - 'PHONE_NUMBER' => '+79788045001', + 'USER_ID' => $userId, + 'PHONE_NUMBER' => $phoneNumber, 'CALL_START_DATE' => $callStartDate, - 'CRM_CREATE' => 1, + 'CRM_CREATE' => 0, 'CRM_SOURCE' => '1', 'CRM_ENTITY_TYPE' => 'LEAD', 'CRM_ENTITY_ID' => $leadId, 'SHOW' => 1, 'CALL_LIST_ID' => 1, - 'LINE_NUMBER' => '+79767867656', - 'TYPE' => 1 + 'LINE_NUMBER' => $phoneNumber, + 'TYPE' => 1, ])->getExternalCallRegister(); - $newRes = $this->externalCallService->finishCall([ - 'CALL_ID'=>$res->CALL_ID, - 'USER_ID'=>$userId, - 'DURATION'=>255, - 'COST'=>5000, - 'COST_CURRENCY'=>'RUB', - 'STATUS_CODE'=>'VI_STATUS_304', - 'FAILED_REASON'=>'', - 'RECORD_URL'=>'', - 'VOTE'=>5, - 'ADD_TO_CHAT'=>1 - ])->getExternalCallFinish(); - var_dump($newRes); - self::assertTrue((bool)$newRes); - self::assertContains($res->CALL_ID,$newRes); + $finishCallResult = $this->externalCallService->finish([ + 'CALL_ID' => $registerCallResult->CALL_ID, + 'USER_ID' => $userId, + 'DURATION' => 255, + 'COST' => 250, + 'COST_CURRENCY' => 'RUB', + 'STATUS_CODE' => 'VI_STATUS_200', + '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'); } /** @@ -167,45 +217,56 @@ public function testFinishCall(): void * @throws Exception * @covers ExternalCall::attachRecord */ - public function testRecordCall(): void + public function testAttachRecord(): void { (string)$datetime = new DateTime('now'); $callStartDate = $datetime->format(DateTimeInterface::ATOM); - $leadId = $this->leadService->add(['TITLE' => 'test lead'])->getId(); + $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; - $res = $this->externalCallService->registerCall([ + $registerCallResult = $this->externalCallService->registerCall([ 'USER_PHONE_INNER' => '14', - 'user_id' => $userId, - 'PHONE_NUMBER' => '+79788045001', + 'USER_ID' => $userId, + 'PHONE_NUMBER' => $phoneNumber, 'CALL_START_DATE' => $callStartDate, - 'CRM_CREATE' => 1, + 'CRM_CREATE' => 0, 'CRM_SOURCE' => '1', 'CRM_ENTITY_TYPE' => 'LEAD', 'CRM_ENTITY_ID' => $leadId, 'SHOW' => 1, 'CALL_LIST_ID' => 1, - 'LINE_NUMBER' => '+79767867656', - 'TYPE' => 1 - ])->getExternalCallRegister()->CALL_ID; - - $newRes = $this->externalCallService->finishCall([ - 'CALL_ID'=>$res, - 'USER_ID'=>$userId, - 'DURATION'=>255, - 'COST'=>5000, - 'COST_CURRENCY'=>'RUB', - 'STATUS_CODE'=>'VI_STATUS_304', - 'FAILED_REASON'=>'', - 'RECORD_URL'=>'', - 'VOTE'=>5, - 'ADD_TO_CHAT'=>1 + 'LINE_NUMBER' => $phoneNumber, + 'TYPE' => 1, + ])->getExternalCallRegister(); + + $finishCallResult = $this->externalCallService->finish([ + 'CALL_ID' => $registerCallResult->CALL_ID, + 'USER_ID' => $userId, + 'DURATION' => 255, + 'COST' => 250, + 'COST_CURRENCY' => 'RUB', + 'STATUS_CODE' => 'VI_STATUS_200', + 'FAILED_REASON' => '', + 'RECORD_URL' => '', + 'VOTE' => 5, + 'ADD_TO_CHAT' => 1 ])->getExternalCallFinish(); - $fileName = sprintf('test%s', time()); - //Декодирование в base64 разобраться с этим. - $content = 'filesss'; + $fileName = sprintf('test%s.mp3', time()); + // todo Декодирование в base64 разобраться с этим. + $content = sprintf('newContent%s',time()); $url = 'https://vk.com/audio172690992_456241640_4836017d770715b9af'; - self::assertGreaterThan(1, $this->externalCallService->attachRecord($res, $fileName, $content, $url)->getRecord()); + self::assertGreaterThan(1, $this->externalCallService->attachRecord($registerCallResult->CALL_ID, $fileName, $content)->getFileId()); } /** From 6cf1e931d74694c8977259295a64d4fc0774c475 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Thu, 14 Jul 2022 11:56:10 +0300 Subject: [PATCH 369/647] -add telephony.externalCall.attachRecord --- .../Telephony/Service/ExternalCallTest.php | 36 ++++++++++++------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php index c93205ad..916e957f 100644 --- a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php +++ b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php @@ -29,11 +29,9 @@ class ExternalCallTest extends TestCase */ public function testRegisterCall(): void { - //Подготовка данных - // Тест (string)$datetime = new DateTime('now'); $callStartDate = $datetime->format(DateTimeInterface::ATOM); - $phoneNumber = sprintf('+7%s',time()); + $phoneNumber = sprintf('+7%s', time()); $leadId = $this->leadService->add( [ 'TITLE' => 'test lead', @@ -62,10 +60,8 @@ public function testRegisterCall(): void ])->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)); - - + self::assertEquals($registerCallResult->CRM_ENTITY_ID, $leadId, sprintf('registered entity id : %s , and lead id: %s, should not differ', + $registerCallResult->CRM_ENTITY_ID, $leadId)); } /** @@ -105,7 +101,7 @@ public function testShowCallCard(): void 'LINE_NUMBER' => $phoneNumber, 'TYPE' => 1, ])->getExternalCallRegister(); - self::assertTrue($this->externalCallService->show($registerCallResult->CALL_ID,$userId )->isShown()); + self::assertTrue($this->externalCallService->show($registerCallResult->CALL_ID, $userId)->isShown()); } /** @@ -208,7 +204,7 @@ public function testFinish(): void 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'); + self::assertNotEmpty($finishCallResult->PHONE_NUMBER, 'phone number cannot be empty'); } /** @@ -252,7 +248,7 @@ public function testAttachRecord(): void $finishCallResult = $this->externalCallService->finish([ 'CALL_ID' => $registerCallResult->CALL_ID, 'USER_ID' => $userId, - 'DURATION' => 255, + 'DURATION' => 10, 'COST' => 250, 'COST_CURRENCY' => 'RUB', 'STATUS_CODE' => 'VI_STATUS_200', @@ -263,9 +259,7 @@ public function testAttachRecord(): void ])->getExternalCallFinish(); $fileName = sprintf('test%s.mp3', time()); - // todo Декодирование в base64 разобраться с этим. - $content = sprintf('newContent%s',time()); - $url = 'https://vk.com/audio172690992_456241640_4836017d770715b9af'; + $content = $this->getFileInBase64(); self::assertGreaterThan(1, $this->externalCallService->attachRecord($registerCallResult->CALL_ID, $fileName, $content)->getFileId()); } @@ -278,4 +272,20 @@ public function setUp(): void $this->leadService = Fabric::getServiceBuilder()->getCRMScope()->lead(); $this->mainService = Fabric::getServiceBuilder()->getMainScope()->main(); } + + + private function getFileInBase64(): string + { + $filePath = 'C:/users/admin/downloads/'; + $fileName = 'newFile.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 From 49d0ab35f9eb396f7565e329b342f70fa0db4a45 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 14 Jul 2022 12:21:57 +0300 Subject: [PATCH 370/647] add boosty.to Signed-off-by: mesilov --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..36d1495b --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +custom: ["https://boosty.to/bitrix24-php-sdk"] \ No newline at end of file From b0be23150b8b936433c7d2d6868969980d4b6cf5 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 14 Jul 2022 14:10:51 +0300 Subject: [PATCH 371/647] add boosty.to in README.md Signed-off-by: mesilov --- CHANGELOG.md | 4 ++++ README.md | 9 ++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49566977..72a7dc6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,10 @@ * fix error in `RenewedAccessToken` DTO, remove `Scope` enum [UnknownScopeCodeException - in refresh token response](https://github.com/mesilov/bitrix24-php-sdk/issues/295) +### etc + +* add link to [boosty.to/bitrix24-php-sdk](https://boosty.to/bitrix24-php-sdk) for sponsoring development + ## 2.0-alpha.6 — 7.02.2022 ### Added diff --git a/README.md b/README.md index 2656f480..ecb68439 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,10 @@ Performance improvements 🚀 - test coverage: unit, integration, contract - typical examples typical for different modes of operation and they are optimized for memory \ performance +### Sponsors + +Help bitrix24-php-sdk by [boosty.to/bitrix24-php-sdk](https://boosty.to/bitrix24-php-sdk) its development! + ### Architecture ### Abstraction layers @@ -184,7 +188,6 @@ See also the list of [contributors](https://github.com/mesilov/bitrix24-php-sdk/ email: -### Sponsors ### Documentation @@ -217,6 +220,10 @@ email: - покрытие тестами: unit, интеграционные, контрактные - есть типовые примеры характерные для разных режимов работы и они оптимизированы по памяти \ быстродействию +### Спонсоры + +Помогите развитию bitrix24-php-sdk подписавшись на [boosty.to/bitrix24-php-sdk](https://boosty.to/bitrix24-php-sdk)! + ### Ключевые особенности ### Слои SDK From 38f89e92b039814f0a87e79d0614b3f0ea8eee07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Thu, 14 Jul 2022 18:55:39 +0300 Subject: [PATCH 372/647] -edit ExternalCallTest.php -add Enumerations --- src/Services/Telephony/Common/CallType.php | 69 +++++++++++++++++ .../Telephony/Common/CrmEntityType.php | 64 ++++++++++++++++ .../Telephony/Common/StatusCodeInterface.php | 22 ++++++ .../Common/StatusSipRegistrations.php | 74 +++++++++++++++++++ src/Services/Telephony/Common/TypeAtc.php | 52 +++++++++++++ .../Telephony/Service/ExternalCallTest.php | 36 +++++---- 6 files changed, 303 insertions(+), 14 deletions(-) create mode 100644 src/Services/Telephony/Common/CallType.php create mode 100644 src/Services/Telephony/Common/CrmEntityType.php create mode 100644 src/Services/Telephony/Common/StatusCodeInterface.php create mode 100644 src/Services/Telephony/Common/StatusSipRegistrations.php create mode 100644 src/Services/Telephony/Common/TypeAtc.php diff --git a/src/Services/Telephony/Common/CallType.php b/src/Services/Telephony/Common/CallType.php new file mode 100644 index 00000000..f8f52cc5 --- /dev/null +++ b/src/Services/Telephony/Common/CallType.php @@ -0,0 +1,69 @@ +code = $typeCall ; + break; + default: + throw new InvalidArgumentException(sprintf('unknown type call %s', $typeCall)); + } + } + + /** + * @return self + */ + public static function one(): self + { + return new self(self::one); + } + + /** + * @return self + */ + public static function two(): self + { + return new self(self::two); + } + + /** + * @return self + */ + public static function three(): self + { + return new self(self::three); + } + + /** + * @return self + */ + public static function four(): self + { + return new self(self::four); + } + + +} + diff --git a/src/Services/Telephony/Common/CrmEntityType.php b/src/Services/Telephony/Common/CrmEntityType.php new file mode 100644 index 00000000..4784eaea --- /dev/null +++ b/src/Services/Telephony/Common/CrmEntityType.php @@ -0,0 +1,64 @@ +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 self + */ + public static function company(): self + { + return new self(self::company); + } + + /** + * @return self + */ + public static function lead(): self + { + return new self(self::lead); + } + + /** + * @return string + */ + public function __toString(): string + { + return $this->code; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Common/StatusCodeInterface.php b/src/Services/Telephony/Common/StatusCodeInterface.php new file mode 100644 index 00000000..a899aa72 --- /dev/null +++ b/src/Services/Telephony/Common/StatusCodeInterface.php @@ -0,0 +1,22 @@ +code = $typeSip; + break; + default: + throw new InvalidArgumentException(sprintf('unknown status SIP registrations %s', $typeSip)); + } + } + + /** + * @return self + */ + public static function success(): self + { + return new self(self::success); + } + + /** + * @return self + */ + public static function error(): self + { + return new self(self::error); + } + + /** + * @return self + */ + public static function in_progress(): self + { + return new self(self::in_progress); + } + + /** + * @return self + */ + public static function wait(): self + { + return new self(self::wait); + } + + /** + * @return string + */ + public function __toString(): string + { + return $this->code; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Common/TypeAtc.php b/src/Services/Telephony/Common/TypeAtc.php new file mode 100644 index 00000000..6c6f25ca --- /dev/null +++ b/src/Services/Telephony/Common/TypeAtc.php @@ -0,0 +1,52 @@ +code = $typeAtc; + break; + default: + throw new InvalidArgumentException(sprintf('unknown type ATC %s', $typeAtc)); + } + } + + /** + * @return self + */ + public static function cloud(): self + { + return new self(self::cloudAtc); + } + + /** + * @return self + */ + public static function office(): self + { + return new self(self::officeAtc); + } + + /** + * @return string + */ + public function __toString(): string + { + return $this->code; + } +} \ No newline at end of file diff --git a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php index 916e957f..67e56a1f 100644 --- a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php +++ b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php @@ -4,13 +4,17 @@ 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\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\StatusCodeInterface; use Bitrix24\SDK\Services\Telephony\Service\ExternalCall; -use _PHPStan_59fb0a3b2\Nette\Utils\DateTime; use Bitrix24\SDK\Tests\Integration\Fabric; +use DateTime; use DateTimeInterface; use Exception; use PHPUnit\Framework\TestCase; @@ -27,9 +31,10 @@ class ExternalCallTest extends TestCase * @throws Exception * @covers ExternalCall::registerCall */ + public function testRegisterCall(): void { - (string)$datetime = new DateTime('now'); + $datetime = new DateTime('now'); $callStartDate = $datetime->format(DateTimeInterface::ATOM); $phoneNumber = sprintf('+7%s', time()); $leadId = $this->leadService->add( @@ -43,6 +48,7 @@ public function testRegisterCall(): void ] ] )->getId(); + $userId = $this->mainService->getCurrentUserProfile()->getUserProfile()->ID; $registerCallResult = $this->externalCallService->registerCall([ 'USER_PHONE_INNER' => '14', @@ -51,7 +57,7 @@ public function testRegisterCall(): void 'CALL_START_DATE' => $callStartDate, 'CRM_CREATE' => 0, 'CRM_SOURCE' => '1', - 'CRM_ENTITY_TYPE' => 'LEAD', + 'CRM_ENTITY_TYPE' => CrmEntityType::lead(), 'CRM_ENTITY_ID' => $leadId, 'SHOW' => 1, 'CALL_LIST_ID' => 1, @@ -70,9 +76,11 @@ public function testRegisterCall(): void * @throws Exception * @covers ExternalCall::show */ + + public function testShowCallCard(): void { - (string)$datetime = new DateTime('now'); + $datetime = new DateTime('now'); $callStartDate = $datetime->format(DateTimeInterface::ATOM); $phoneNumber = '+79788045001'; $leadId = $this->leadService->add( @@ -94,7 +102,7 @@ public function testShowCallCard(): void 'CALL_START_DATE' => $callStartDate, 'CRM_CREATE' => 0, 'CRM_SOURCE' => '1', - 'CRM_ENTITY_TYPE' => 'LEAD', + 'CRM_ENTITY_TYPE' => CrmEntityType::lead(), 'CRM_ENTITY_ID' => $leadId, 'SHOW' => 0, 'CALL_LIST_ID' => 1, @@ -112,7 +120,7 @@ public function testShowCallCard(): void */ public function testHideCallCard(): void { - (string)$datetime = new DateTime('now'); + $datetime = new DateTime('now'); $callStartDate = $datetime->format(DateTimeInterface::ATOM); $phoneNumber = '+79788045001'; $leadId = $this->leadService->add( @@ -134,7 +142,7 @@ public function testHideCallCard(): void 'CALL_START_DATE' => $callStartDate, 'CRM_CREATE' => 0, 'CRM_SOURCE' => '1', - 'CRM_ENTITY_TYPE' => 'LEAD', + 'CRM_ENTITY_TYPE' => CrmEntityType::lead(), 'CRM_ENTITY_ID' => $leadId, 'SHOW' => 0, 'CALL_LIST_ID' => 1, @@ -152,7 +160,7 @@ public function testHideCallCard(): void */ public function testFinish(): void { - (string)$datetime = new DateTime('now'); + $datetime = new DateTime('now'); $callStartDate = $datetime->format(DateTimeInterface::ATOM); $phoneNumber = sprintf('+7%s', time()); $leadId = $this->leadService->add( @@ -188,7 +196,7 @@ public function testFinish(): void 'DURATION' => 255, 'COST' => 250, 'COST_CURRENCY' => 'RUB', - 'STATUS_CODE' => 'VI_STATUS_200', + 'STATUS_CODE' => StatusCodeInterface::statusSuccessfulCall, 'FAILED_REASON' => '', 'RECORD_URL' => '', 'VOTE' => 5, @@ -215,7 +223,7 @@ public function testFinish(): void */ public function testAttachRecord(): void { - (string)$datetime = new DateTime('now'); + $datetime = new DateTime('now'); $callStartDate = $datetime->format(DateTimeInterface::ATOM); $phoneNumber = sprintf('+7%s', time()); $leadId = $this->leadService->add( @@ -229,6 +237,7 @@ public function testAttachRecord(): void ] ] )->getId(); + var_dump(CallType::one()); $userId = $this->mainService->getCurrentUserProfile()->getUserProfile()->ID; $registerCallResult = $this->externalCallService->registerCall([ 'USER_PHONE_INNER' => '14', @@ -259,8 +268,7 @@ public function testAttachRecord(): void ])->getExternalCallFinish(); $fileName = sprintf('test%s.mp3', time()); - $content = $this->getFileInBase64(); - self::assertGreaterThan(1, $this->externalCallService->attachRecord($registerCallResult->CALL_ID, $fileName, $content)->getFileId()); + self::assertGreaterThan(1, $this->externalCallService->attachRecord($registerCallResult->CALL_ID, $fileName, $this->getFileInBase64())->getFileId()); } /** @@ -276,8 +284,8 @@ public function setUp(): void private function getFileInBase64(): string { - $filePath = 'C:/users/admin/downloads/'; - $fileName = 'newFile.mp3'; + $filePath = __DIR__ . '/TestFile/'; + $fileName = 'callRecording.mp3'; $resBase64 = ''; $handle = fopen($filePath . $fileName, "rb"); if ($handle) { From 9e9a35a4991203f542f4aa94a2511d37832017c0 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 14 Jul 2022 23:43:07 +0300 Subject: [PATCH 373/647] add support for PortalDomainUrlChangedEvent Signed-off-by: mesilov --- CHANGELOG.md | 3 +- src/Core/Core.php | 25 ++++++++++++++ src/Core/Credentials/Credentials.php | 31 ++++++++++++----- src/Events/AuthTokenRenewedEvent.php | 5 +-- src/Events/PortalDomainUrlChangedEvent.php | 39 ++++++++++++++++++++++ 5 files changed, 90 insertions(+), 13 deletions(-) create mode 100644 src/Events/PortalDomainUrlChangedEvent.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 72a7dc6e..7e0d314d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # bitrix24-php-sdk change log -## 2.0-alpha.7 — 15.07.2022 +## 2.0-alpha.7 — 25.07.2022 ### Added @@ -11,6 +11,7 @@ * add in scope «Main» new service `Events` [add incoming events support](https://github.com/mesilov/bitrix24-php-sdk/issues/296) * add support Application level events: `ONAPPINSTALL` and `ONAPPUNINSTALL` [add incoming events support](https://github.com/mesilov/bitrix24-php-sdk/issues/296) +* add support Application level event: `PortalDomainUrlChangedEvent` * add method `Core\Batch::updateEntityItems` for [update items in batch mode](https://github.com/mesilov/bitrix24-php-sdk/issues/268) and integration test * add method to interface `Core\Contracts\BatchInterface::updateEntityItems` for update items in batch mode diff --git a/src/Core/Core.php b/src/Core/Core.php index ee67a93e..688bbe26 100644 --- a/src/Core/Core.php +++ b/src/Core/Core.php @@ -11,6 +11,7 @@ use Bitrix24\SDK\Core\Exceptions\TransportException; use Bitrix24\SDK\Core\Response\Response; use Bitrix24\SDK\Events\AuthTokenRenewedEvent; +use Bitrix24\SDK\Events\PortalDomainUrlChangedEvent; use Fig\Http\Message\StatusCodeInterface; use Psr\Log\LoggerInterface; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; @@ -81,6 +82,30 @@ public function call(string $apiMethod, array $parameters = []): Response //todo check with empty response size from server $response = new Response($apiCallResponse, new Command($apiMethod, $parameters), $this->logger); break; + case StatusCodeInterface::STATUS_FOUND: + // change domain url + $portalOldDomainUrlHost = $this->apiClient->getCredentials()->getDomainUrl(); + $newDomain = parse_url($apiCallResponse->getHeaders(false)['location'][0]); + $portalNewDomainUrlHost = sprintf('%s://%s', $newDomain['scheme'], $newDomain['host']); + $this->apiClient->getCredentials()->setDomainUrl($portalNewDomainUrlHost); + $this->logger->debug('domain url changed', [ + 'oldDomainUrl' => $portalOldDomainUrlHost, + 'newDomainUrl' => $portalNewDomainUrlHost, + ]); + + // repeat api-call to new domain url + $response = $this->call($apiMethod, $parameters); + $this->logger->debug( + 'api call repeated to new domain url', + [ + 'domainUrl' => $portalNewDomainUrlHost, + 'repeatedApiMethod' => $apiMethod, + 'httpStatusCode' => $response->getHttpResponse()->getStatusCode(), + ] + ); + // dispatch event, application listeners update domain url host in accounts repository + $this->eventDispatcher->dispatch(new PortalDomainUrlChangedEvent($portalOldDomainUrlHost, $portalNewDomainUrlHost)); + break; case StatusCodeInterface::STATUS_UNAUTHORIZED: $body = $apiCallResponse->toArray(false); $this->logger->debug( diff --git a/src/Core/Credentials/Credentials.php b/src/Core/Credentials/Credentials.php index 05c7f8bd..2f38633e 100644 --- a/src/Core/Credentials/Credentials.php +++ b/src/Core/Credentials/Credentials.php @@ -40,15 +40,9 @@ public function __construct( $this->applicationProfile = $applicationProfile; if ($domainUrl !== null) { - $parseResult = parse_url($domainUrl); - if (!array_key_exists('scheme', $parseResult)) { - $domainUrl = 'https://' . $domainUrl; - } + $this->setDomainUrl($domainUrl); } - if (($domainUrl !== null) && filter_var($domainUrl, FILTER_VALIDATE_URL) === false) { - throw new InvalidArgumentException(sprintf('domain URL %s is invalid', $domainUrl)); - } - $this->domainUrl = $domainUrl; + if ($this->accessToken === null && $this->webhookUrl === null) { throw new \LogicException('you must set on of auth type: webhook or OAuth 2.0'); } @@ -65,6 +59,27 @@ public function setAccessToken(AccessToken $accessToken): void $this->accessToken = $accessToken; } + /** + * Set domain url + * + * @param string $domainUrl + * + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public function setDomainUrl(string $domainUrl): void + { + $parseResult = parse_url($domainUrl); + if (!array_key_exists('scheme', $parseResult)) { + $domainUrl = 'https://' . $domainUrl; + } + + if (filter_var($domainUrl, FILTER_VALIDATE_URL) === false) { + throw new InvalidArgumentException(sprintf('domain URL %s is invalid', $domainUrl)); + } + $this->domainUrl = $domainUrl; + } + /** * @return ApplicationProfile|null */ diff --git a/src/Events/AuthTokenRenewedEvent.php b/src/Events/AuthTokenRenewedEvent.php index 96a6f1b1..3dcb0eb2 100644 --- a/src/Events/AuthTokenRenewedEvent.php +++ b/src/Events/AuthTokenRenewedEvent.php @@ -14,10 +14,7 @@ */ class AuthTokenRenewedEvent extends Event { - /** - * @var RenewedAccessToken - */ - private $renewedToken; + private RenewedAccessToken $renewedToken; /** * AuthTokenRenewedEvent constructor. diff --git a/src/Events/PortalDomainUrlChangedEvent.php b/src/Events/PortalDomainUrlChangedEvent.php new file mode 100644 index 00000000..dc948537 --- /dev/null +++ b/src/Events/PortalDomainUrlChangedEvent.php @@ -0,0 +1,39 @@ +oldDomainUrlHost = parse_url($oldDomainUrlHost, PHP_URL_HOST); + $this->newDomainUrlHost = parse_url($newDomainUrlHost, PHP_URL_HOST); + } + + /** + * @return string + */ + public function getOldDomainUrlHost(): string + { + return $this->oldDomainUrlHost; + } + + /** + * @return string + */ + public function getNewDomainUrlHost(): string + { + return $this->newDomainUrlHost; + } +} \ No newline at end of file From 1520b90feac37bd6fe6aff4247ee77a7e7442fc5 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 14 Jul 2022 23:54:23 +0300 Subject: [PATCH 374/647] disable redirects Signed-off-by: mesilov --- src/Core/ApiClient.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Core/ApiClient.php b/src/Core/ApiClient.php index b637a71c..46ab0497 100644 --- a/src/Core/ApiClient.php +++ b/src/Core/ApiClient.php @@ -143,8 +143,10 @@ public function getResponse(string $apiMethod, array $parameters = []): Response } $requestOptions = [ - 'json' => $parameters, - 'headers' => $this->getDefaultHeaders(), + 'json' => $parameters, + 'headers' => $this->getDefaultHeaders(), + // disable redirects, try to catch portal change domain name event + 'max_redirects' => 0, ]; $response = $this->client->request($method, $url, $requestOptions); From 1af0750444ed3597c1d22589eb556b8247e64ab6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Fri, 15 Jul 2022 12:08:56 +0300 Subject: [PATCH 375/647] -edit CallType.php --- src/Services/Telephony/Common/CallType.php | 64 ++++++------------- .../Telephony/Service/ExternalCallTest.php | 17 +++-- 2 files changed, 29 insertions(+), 52 deletions(-) diff --git a/src/Services/Telephony/Common/CallType.php b/src/Services/Telephony/Common/CallType.php index f8f52cc5..d4d44ea9 100644 --- a/src/Services/Telephony/Common/CallType.php +++ b/src/Services/Telephony/Common/CallType.php @@ -8,62 +8,40 @@ class CallType { - private const one = 1; - private const two = 2; - private const three = 3; - private const four = 4; + + public const one = 1; + public const two = 2; + public const three = 3; + public const four = 4; + private int $code; /** - * + * @param int $code * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException */ - private function __construct($typeCall) - { - switch ($typeCall) { - case $this::one: - case $this::two: - case $this::three: - case $this::four: - $this->code = $typeCall ; - break; - default: - throw new InvalidArgumentException(sprintf('unknown type call %s', $typeCall)); - } - } - /** - * @return self - */ - public static function one(): self + private function __construct(int $code) { - return new self(self::one); - } - - /** - * @return self - */ - public static function two(): self - { - return new self(self::two); - } + if + ( + self::one !== $code && + self::two !== $code && + self::three !== $code && + self::four !== $code + ) { + throw new InvalidArgumentException(sprintf('unknown type call %s', $code)); + } + $this->code = $code; - /** - * @return self - */ - public static function three(): self - { - return new self(self::three); } /** - * @return self + * @return int */ - public static function four(): self + public function getValue(): int { - return new self(self::four); + return $this->code; } - - } diff --git a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php index 67e56a1f..4083e0ed 100644 --- a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php +++ b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php @@ -62,7 +62,7 @@ public function testRegisterCall(): void 'SHOW' => 1, 'CALL_LIST_ID' => 1, 'LINE_NUMBER' => $phoneNumber, - 'TYPE' => 1, + 'TYPE' => CallType::one, ])->getExternalCallRegister(); self::assertTrue((bool)$registerCallResult); @@ -107,7 +107,7 @@ public function testShowCallCard(): void 'SHOW' => 0, 'CALL_LIST_ID' => 1, 'LINE_NUMBER' => $phoneNumber, - 'TYPE' => 1, + 'TYPE' => CallType::one, ])->getExternalCallRegister(); self::assertTrue($this->externalCallService->show($registerCallResult->CALL_ID, $userId)->isShown()); } @@ -147,7 +147,7 @@ public function testHideCallCard(): void 'SHOW' => 0, 'CALL_LIST_ID' => 1, 'LINE_NUMBER' => $phoneNumber, - 'TYPE' => 1, + 'TYPE' => CallType::one, ])->getExternalCallRegister(); self::assertTrue($this->externalCallService->hide($registerCallResult->CALL_ID, $userId)->isHided()); } @@ -187,7 +187,7 @@ public function testFinish(): void 'SHOW' => 1, 'CALL_LIST_ID' => 1, 'LINE_NUMBER' => $phoneNumber, - 'TYPE' => 1, + 'TYPE' => CallType::one, ])->getExternalCallRegister(); $finishCallResult = $this->externalCallService->finish([ @@ -237,7 +237,6 @@ public function testAttachRecord(): void ] ] )->getId(); - var_dump(CallType::one()); $userId = $this->mainService->getCurrentUserProfile()->getUserProfile()->ID; $registerCallResult = $this->externalCallService->registerCall([ 'USER_PHONE_INNER' => '14', @@ -251,7 +250,7 @@ public function testAttachRecord(): void 'SHOW' => 1, 'CALL_LIST_ID' => 1, 'LINE_NUMBER' => $phoneNumber, - 'TYPE' => 1, + 'TYPE' => CallType::one, ])->getExternalCallRegister(); $finishCallResult = $this->externalCallService->finish([ @@ -289,9 +288,9 @@ private function getFileInBase64(): string $resBase64 = ''; $handle = fopen($filePath . $fileName, "rb"); if ($handle) { - $buffer = fread($handle, filesize($filePath.$fileName)); - $resBase64 = base64_encode($buffer); - } + $buffer = fread($handle, filesize($filePath . $fileName)); + $resBase64 = base64_encode($buffer); + } fclose($handle); return $resBase64; From 90d6c107910ca1841762e8bceb3683ecff94f17a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Fri, 15 Jul 2022 14:03:21 +0300 Subject: [PATCH 376/647] -edit CallType.php and StatusCodeInterface.php --- src/Services/Telephony/Common/CallType.php | 70 ++++++++++++++----- .../Telephony/Common/StatusCodeInterface.php | 24 +++---- 2 files changed, 62 insertions(+), 32 deletions(-) diff --git a/src/Services/Telephony/Common/CallType.php b/src/Services/Telephony/Common/CallType.php index d4d44ea9..39239fac 100644 --- a/src/Services/Telephony/Common/CallType.php +++ b/src/Services/Telephony/Common/CallType.php @@ -9,39 +9,71 @@ class CallType { - public const one = 1; - public const two = 2; - public const three = 3; - public const four = 4; - - private int $code; + private const outboundCall = '1'; + private const inboundCall = '2'; + private const inboundCallWithRedirection = '3'; + private const backCall = '4'; + private string $code; /** - * @param int $code + * @param string $typeCode * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException */ - private function __construct(int $code) + private function __construct(string $typeCode) { - if - ( - self::one !== $code && - self::two !== $code && - self::three !== $code && - self::four !== $code - ) { - throw new InvalidArgumentException(sprintf('unknown type call %s', $code)); + switch ($typeCode) { + case $this::inboundCall: + case $this::outboundCall: + case $this::inboundCallWithRedirection: + case $this::backCall: + $this->code = $typeCode; + break; + default: + throw new InvalidArgumentException(sprintf('unknown type call %s', $typeCode)); } - $this->code = $code; + } + + /** + * @return string + */ + public static function outboundCall(): string + { + return self::outboundCall; } /** - * @return int + * @return string */ - public function getValue(): int + + public static function inboundCall(): string + { + return self::inboundCall; + } + + /** + * @return string + */ + + public static function inboundCallWithRedirection(): string + { + return self::inboundCallWithRedirection; + } + + /** + * @return string + */ + + public static function backCall(): string + { + return self::backCall; + } + + public function __toString(): string { return $this->code; } + } diff --git a/src/Services/Telephony/Common/StatusCodeInterface.php b/src/Services/Telephony/Common/StatusCodeInterface.php index a899aa72..791f43b4 100644 --- a/src/Services/Telephony/Common/StatusCodeInterface.php +++ b/src/Services/Telephony/Common/StatusCodeInterface.php @@ -6,17 +6,15 @@ interface StatusCodeInterface { - public const statusSuccessfulCall = 'VI_STATUS_200'; - public const statusMissedCall = 'VI_STATUS_304'; - public const statusRejected = 'VI_STATUS_603'; - public const statusCanceledCall = 'VI_STATUS_603-S'; - public const statusForbidden = 'VI_STATUS_403'; - public const statusWrongNumber = 'VI_STATUS_404'; - public const statusBusy = 'VI_STATUS_486'; - public const statusThisRouteIsNotAvailable = 'VI_STATUS_484'; - public const statusTemporarilyUnavailable = 'VI_STATUS_480'; - public const statusInsufficientFundsInTheAccount ='VI_STATUS_402'; - public const statusBlocked = 'VI_STATUS_423'; - public const statusNotDetermined = 'VI_STATUS_OTHER'; - + const STATUS_OK = 200; + const STATUS_NOT_MODIFIED = 304; + const STATUS_DECLINE = 603; + const STATUS_FORBIDDEN = 403; + const STATUS_NOT_FOUND = 404; + const STATUS_BUSY_HERE = 486; + const STATUS_ADDRESS_INCOMPLETE= 484; + const STATUS_SERVICE_UNAVAILABLE = 503; + const STATUS_TEMPORARILY_UNAVAILABLE = 480; + const STATUS_PAYMENT_REQUIRED = 402; + const STATUS_INTERVAL_TOO_BRIEF = 423; } \ No newline at end of file From 7ddb04a36cbb24d6fc4e57868e9e8a12c8fbb2b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Fri, 15 Jul 2022 14:12:22 +0300 Subject: [PATCH 377/647] -edit ExternalCallTest.php --- .../Services/Telephony/Service/ExternalCallTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php index 4083e0ed..59b04187 100644 --- a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php +++ b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php @@ -62,7 +62,7 @@ public function testRegisterCall(): void 'SHOW' => 1, 'CALL_LIST_ID' => 1, 'LINE_NUMBER' => $phoneNumber, - 'TYPE' => CallType::one, + 'TYPE' => CallType::inboundCall(), ])->getExternalCallRegister(); self::assertTrue((bool)$registerCallResult); @@ -196,7 +196,7 @@ public function testFinish(): void 'DURATION' => 255, 'COST' => 250, 'COST_CURRENCY' => 'RUB', - 'STATUS_CODE' => StatusCodeInterface::statusSuccessfulCall, + 'STATUS_CODE' => StatusCodeInterface::STATUS_OK, 'FAILED_REASON' => '', 'RECORD_URL' => '', 'VOTE' => 5, @@ -284,7 +284,7 @@ public function setUp(): void private function getFileInBase64(): string { $filePath = __DIR__ . '/TestFile/'; - $fileName = 'callRecording.mp3'; + $fileName = 'test-phone-record.mp3'; $resBase64 = ''; $handle = fopen($filePath . $fileName, "rb"); if ($handle) { From a38d30bcfff14d98f23fa9ee60acf9f6a9ffb308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Fri, 15 Jul 2022 17:09:55 +0300 Subject: [PATCH 378/647] -edit CallType.php -add new status in StatusSipCodeInterface.php --- src/Services/Telephony/Common/CallType.php | 29 +++--- .../Telephony/Common/StatusCodeInterface.php | 20 ---- .../Common/StatusSipCodeInterface.php | 94 +++++++++++++++++++ .../Telephony/Service/ExternalCallTest.php | 17 ++-- 4 files changed, 119 insertions(+), 41 deletions(-) delete mode 100644 src/Services/Telephony/Common/StatusCodeInterface.php create mode 100644 src/Services/Telephony/Common/StatusSipCodeInterface.php diff --git a/src/Services/Telephony/Common/CallType.php b/src/Services/Telephony/Common/CallType.php index 39239fac..392e3243 100644 --- a/src/Services/Telephony/Common/CallType.php +++ b/src/Services/Telephony/Common/CallType.php @@ -8,25 +8,24 @@ class CallType { - - private const outboundCall = '1'; - private const inboundCall = '2'; - private const inboundCallWithRedirection = '3'; - private const backCall = '4'; - private string $code; + 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 string $typeCode + * @param int $typeCode * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException */ - private function __construct(string $typeCode) + private function __construct(int $typeCode) { switch ($typeCode) { - case $this::inboundCall: - case $this::outboundCall: - case $this::inboundCallWithRedirection: - case $this::backCall: + case $this::INBOUND_CALL: + case $this::OUTBOUND_CALL: + case $this::INBOUND_CALL_WITH_REDIRECTION: + case $this::CALLBACK: $this->code = $typeCode; break; default: @@ -62,17 +61,17 @@ public static function inboundCallWithRedirection(): string } /** - * @return string + * @return self */ public static function backCall(): string { - return self::backCall; + return new self( self::CALLBACK); } public function __toString(): string { - return $this->code; + return (string)$this->code; } } diff --git a/src/Services/Telephony/Common/StatusCodeInterface.php b/src/Services/Telephony/Common/StatusCodeInterface.php deleted file mode 100644 index 791f43b4..00000000 --- a/src/Services/Telephony/Common/StatusCodeInterface.php +++ /dev/null @@ -1,20 +0,0 @@ - 0, 'CALL_LIST_ID' => 1, 'LINE_NUMBER' => $phoneNumber, - 'TYPE' => CallType::one, + 'TYPE' => (string)CallType::inboundCall(), ])->getExternalCallRegister(); self::assertTrue($this->externalCallService->show($registerCallResult->CALL_ID, $userId)->isShown()); } @@ -147,7 +147,7 @@ public function testHideCallCard(): void 'SHOW' => 0, 'CALL_LIST_ID' => 1, 'LINE_NUMBER' => $phoneNumber, - 'TYPE' => CallType::one, + 'TYPE' => (string)CallType::inboundCall(), ])->getExternalCallRegister(); self::assertTrue($this->externalCallService->hide($registerCallResult->CALL_ID, $userId)->isHided()); } @@ -187,7 +187,7 @@ public function testFinish(): void 'SHOW' => 1, 'CALL_LIST_ID' => 1, 'LINE_NUMBER' => $phoneNumber, - 'TYPE' => CallType::one, + 'TYPE' => (string)CallType::inboundCall(), ])->getExternalCallRegister(); $finishCallResult = $this->externalCallService->finish([ @@ -196,7 +196,7 @@ public function testFinish(): void 'DURATION' => 255, 'COST' => 250, 'COST_CURRENCY' => 'RUB', - 'STATUS_CODE' => StatusCodeInterface::STATUS_OK, + 'STATUS_CODE' => StatusSipCodeInterface::STATUS_OK, 'FAILED_REASON' => '', 'RECORD_URL' => '', 'VOTE' => 5, @@ -250,7 +250,7 @@ public function testAttachRecord(): void 'SHOW' => 1, 'CALL_LIST_ID' => 1, 'LINE_NUMBER' => $phoneNumber, - 'TYPE' => CallType::one, + 'TYPE' => (string)CallType::inboundCall(), ])->getExternalCallRegister(); $finishCallResult = $this->externalCallService->finish([ @@ -270,6 +270,11 @@ public function testAttachRecord(): void self::assertGreaterThan(1, $this->externalCallService->attachRecord($registerCallResult->CALL_ID, $fileName, $this->getFileInBase64())->getFileId()); } + public function testSearchCrmEntities():void + { + + } + /** * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException */ From 70ae050989ce832b6f4b5b240c24dcd7c236e76f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Fri, 15 Jul 2022 18:32:02 +0300 Subject: [PATCH 379/647] -add new method telephony.externalCall.searchCrmEntities --- ...xternalCallSearchCrmEntitiesItemResult.php | 19 ++++++ .../ExternalCallSearchCrmEntitiesResult.php | 19 ++++++ .../Telephony/Service/ExternalCall.php | 59 ++++++++++++++----- .../Telephony/Service/ExternalCallTest.php | 52 ++++++++++++++++ 4 files changed, 133 insertions(+), 16 deletions(-) create mode 100644 src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesItemResult.php create mode 100644 src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesResult.php diff --git a/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesItemResult.php b/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesItemResult.php new file mode 100644 index 00000000..e95b9677 --- /dev/null +++ b/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesItemResult.php @@ -0,0 +1,19 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData()); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Service/ExternalCall.php b/src/Services/Telephony/Service/ExternalCall.php index 0d90ba33..d020a0c6 100644 --- a/src/Services/Telephony/Service/ExternalCall.php +++ b/src/Services/Telephony/Service/ExternalCall.php @@ -9,10 +9,12 @@ 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{ +class ExternalCall extends AbstractService +{ /** * The method registers a call in Bitrix24 * @@ -42,8 +44,8 @@ public function registerCall(array $fields): ExternalCallRegisterResult { return new ExternalCallRegisterResult( $this->core->call( - 'telephony.externalcall.register', - $fields, + 'telephony.externalcall.register', + $fields, ) ); } @@ -61,13 +63,14 @@ public function registerCall(array $fields): ExternalCallRegisterResult * @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{ + public function show(string $callId, int $userId): ExternalCallShowResult + { return new ExternalCallShowResult( $this->core->call( 'telephony.externalcall.show', [ - 'CALL_ID'=>$callId, - 'USER_ID'=>$userId, + 'CALL_ID' => $callId, + 'USER_ID' => $userId, ] ) ); @@ -86,13 +89,14 @@ public function show(string $callId, int $userId):ExternalCallShowResult{ * @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{ + public function hide(string $callId, int $userId): ExternalCallHideResult + { return new ExternalCallHideResult( $this->core->call( 'telephony.externalcall.hide', [ - 'CALL_ID'=>$callId, - 'USER_ID'=>$userId, + 'CALL_ID' => $callId, + 'USER_ID' => $userId, ] ) ); @@ -119,7 +123,7 @@ public function hide(string $callId, int $userId):ExternalCallHideResult{ * @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 + public function finish(array $fields): ExternalCallFinishResult { return new ExternalCallFinishResult( $this->core->call( @@ -135,23 +139,46 @@ public function finish(array $fields):ExternalCallFinishResult * @param string $callId * @param string $fileName * @param string $fileContent - * @param string $recordUrl + * @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 + 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, + '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. + * + * @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, ] ) ); diff --git a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php index fd23df19..79d9ec31 100644 --- a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php +++ b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php @@ -270,9 +270,61 @@ public function testAttachRecord(): void self::assertGreaterThan(1, $this->externalCallService->attachRecord($registerCallResult->CALL_ID, $fileName, $this->getFileInBase64())->getFileId()); } + /** + * @throws TransportException + * @throws BaseException + * @throws Exception + * @covers ExternalCall::searchCrmEntities + */ public function testSearchCrmEntities():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' => '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(); + + $infoAboutClientResult = $this->externalCallService->searchCrmEntities($phoneNumber)->getCrmEntitiesClient(); + self::assertNotEmpty($phoneNumber); + self::assertTrue((bool)$infoAboutClientResult); } /** From 6bbbe00bd634bb70e0d751f51492cd0f8a73f0a9 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 16 Jul 2022 16:03:48 +0300 Subject: [PATCH 380/647] add activity read models Signed-off-by: mesilov --- CHANGELOG.md | 6 +- .../CRM/Activity/ActivityFetcherBuilder.php | 63 +++++++++++++++++++ .../CRM/Activity/ReadModel/EmailFetcher.php | 44 +++++++++++++ .../Activity/ReadModel/OpenLineFetcher.php | 49 +++++++++++++++ .../Activity/ReadModel/VoximplantFetcher.php | 44 +++++++++++++ .../CRM/Activity/ReadModel/WebFormFetcher.php | 48 ++++++++++++++ .../Activity/Result/ActivityItemResult.php | 8 +-- .../Result/Email/EmailActivityItemResult.php | 22 +++++++ .../CRM/Activity/Result/Email/EmailMeta.php | 19 ++++++ .../Activity/Result/Email/EmailSettings.php | 28 +++++++++ .../OpenLine/OpenLineActivityItemResult.php | 18 ++++++ .../OpenLine/OpenLineProviderParams.php | 43 +++++++++++++ .../Result/WebForm/VisitedPageItem.php | 18 ++++++ .../WebForm/WebFormActivityItemResult.php | 27 ++++++++ .../Result/WebForm/WebFormFieldItem.php | 20 ++++++ .../Result/WebForm/WebFormMetadata.php | 60 ++++++++++++++++++ .../Result/WebForm/WebFormProviderParams.php | 59 +++++++++++++++++ src/Services/CRM/CRMServiceBuilder.php | 17 +++++ .../Activity/ReadModel/EmailFetcherTest.php | 40 ++++++++++++ .../ReadModel/OpenLineFetcherTest.php | 40 ++++++++++++ .../ReadModel/VoximplantFetcherTest.php | 41 ++++++++++++ .../Activity/ReadModel/WebFormFetcherTest.php | 40 ++++++++++++ 22 files changed, 748 insertions(+), 6 deletions(-) create mode 100644 src/Services/CRM/Activity/ActivityFetcherBuilder.php create mode 100644 src/Services/CRM/Activity/ReadModel/EmailFetcher.php create mode 100644 src/Services/CRM/Activity/ReadModel/OpenLineFetcher.php create mode 100644 src/Services/CRM/Activity/ReadModel/VoximplantFetcher.php create mode 100644 src/Services/CRM/Activity/ReadModel/WebFormFetcher.php create mode 100644 src/Services/CRM/Activity/Result/Email/EmailActivityItemResult.php create mode 100644 src/Services/CRM/Activity/Result/Email/EmailMeta.php create mode 100644 src/Services/CRM/Activity/Result/Email/EmailSettings.php create mode 100644 src/Services/CRM/Activity/Result/OpenLine/OpenLineActivityItemResult.php create mode 100644 src/Services/CRM/Activity/Result/OpenLine/OpenLineProviderParams.php create mode 100644 src/Services/CRM/Activity/Result/WebForm/VisitedPageItem.php create mode 100644 src/Services/CRM/Activity/Result/WebForm/WebFormActivityItemResult.php create mode 100644 src/Services/CRM/Activity/Result/WebForm/WebFormFieldItem.php create mode 100644 src/Services/CRM/Activity/Result/WebForm/WebFormMetadata.php create mode 100644 src/Services/CRM/Activity/Result/WebForm/WebFormProviderParams.php create mode 100644 tests/Integration/Services/CRM/Activity/ReadModel/EmailFetcherTest.php create mode 100644 tests/Integration/Services/CRM/Activity/ReadModel/OpenLineFetcherTest.php create mode 100644 tests/Integration/Services/CRM/Activity/ReadModel/VoximplantFetcherTest.php create mode 100644 tests/Integration/Services/CRM/Activity/ReadModel/WebFormFetcherTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e0d314d..1bbab3f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ * add new scope `Placements` and services [add Placements support](https://github.com/mesilov/bitrix24-php-sdk/issues/274) * add in scope `CRM` new service `Leads` in scope «CRM» [add Leads support](https://github.com/mesilov/bitrix24-php-sdk/issues/282) * add in scope `CRM` new service `Activity` in scope «CRM» [add Activity support](https://github.com/mesilov/bitrix24-php-sdk/issues/283) +* add in scope `CRM` for entity Deal method `Services\CRM\Deal\Service\Batch::update` batch update deals +* add in scope `CRM` for entity Contact method `Services\CRM\Contact\Service\Batch::delete` batch delete contacts +* add in scope `CRM` [read models](https://github.com/mesilov/bitrix24-php-sdk/issues/300) for activity `Services\CRM\Activity\ReadModel` + for activity types: `EmailFetcher`, `OpenLineFetcher`, `VoximplantFetcher`, `WebFormFetcher` * add in scope «Main» new service `Events` [add incoming events support](https://github.com/mesilov/bitrix24-php-sdk/issues/296) * add support Application level events: `ONAPPINSTALL` and `ONAPPUNINSTALL` [add incoming events support](https://github.com/mesilov/bitrix24-php-sdk/issues/296) @@ -15,8 +19,6 @@ * add method `Core\Batch::updateEntityItems` for [update items in batch mode](https://github.com/mesilov/bitrix24-php-sdk/issues/268) and integration test * add method to interface `Core\Contracts\BatchInterface::updateEntityItems` for update items in batch mode -* add in scope `CRM` for entity Deal method `Services\CRM\Deal\Service\Batch::update` batch update deals -* add in scope `CRM` for entity Contact method `Services\CRM\Contact\Service\Batch::delete` batch delete contacts * add in scope `Placements` service `Placement\Service\UserFieldType` for work with user fields embedding * add `ApplicationStatus` with application status codes description * add fabric method `AccessToken::initFromPlacementRequest` when application init form placement request diff --git a/src/Services/CRM/Activity/ActivityFetcherBuilder.php b/src/Services/CRM/Activity/ActivityFetcherBuilder.php new file mode 100644 index 00000000..e4508320 --- /dev/null +++ b/src/Services/CRM/Activity/ActivityFetcherBuilder.php @@ -0,0 +1,63 @@ +serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Activity\ReadModel\EmailFetcher($this->bulkItemsReader); + } + + return $this->serviceCache[__METHOD__]; + } + + /** + * @return \Bitrix24\SDK\Services\CRM\Activity\ReadModel\OpenLineFetcher + */ + public function openLineFetcher(): Activity\ReadModel\OpenLineFetcher + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Activity\ReadModel\OpenLineFetcher($this->bulkItemsReader); + } + + return $this->serviceCache[__METHOD__]; + } + + /** + * @return \Bitrix24\SDK\Services\CRM\Activity\ReadModel\VoximplantFetcher + */ + public function voximplantFetcher(): Activity\ReadModel\VoximplantFetcher + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Activity\ReadModel\VoximplantFetcher($this->bulkItemsReader); + } + + return $this->serviceCache[__METHOD__]; + } + + /** + * @return \Bitrix24\SDK\Services\CRM\Activity\ReadModel\WebFormFetcher + */ + public function webFormFetcher(): Activity\ReadModel\WebFormFetcher + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Activity\ReadModel\WebFormFetcher($this->bulkItemsReader); + } + + return $this->serviceCache[__METHOD__]; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/ReadModel/EmailFetcher.php b/src/Services/CRM/Activity/ReadModel/EmailFetcher.php new file mode 100644 index 00000000..2b42e249 --- /dev/null +++ b/src/Services/CRM/Activity/ReadModel/EmailFetcher.php @@ -0,0 +1,44 @@ +bulkItemsReader = $bulkItemsReader; + } + + /** + * @param array $order + * @param array $filter + * @param array $select + * @param int|null $limit + * + * @return EmailActivityItemResult[]|Generator + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function getList(array $order, array $filter, array $select, ?int $limit = null): Generator + { + $filter = array_merge($filter, [ + 'PROVIDER_ID' => 'CRM_EMAIL', + 'PROVIDER_TYPE_ID' => 'EMAIL', + ]); + + foreach ($this->bulkItemsReader->getTraversableList('crm.activity.list', $order, $filter, $select, $limit) as $cnt => $item) { + yield $cnt => new EmailActivityItemResult($item); + } + } +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/ReadModel/OpenLineFetcher.php b/src/Services/CRM/Activity/ReadModel/OpenLineFetcher.php new file mode 100644 index 00000000..baa946be --- /dev/null +++ b/src/Services/CRM/Activity/ReadModel/OpenLineFetcher.php @@ -0,0 +1,49 @@ +bulkItemsReader = $bulkItemsReader; + } + + /** + * @param array $order + * @param array $filter + * @param array $select + * @param int|null $openLineTypeId + * @param int|null $limit + * + * @return OpenLineActivityItemResult[]|Generator + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function getList(array $order, array $filter, array $select, ?int $openLineTypeId = null, ?int $limit = null): Generator + { + if ($openLineTypeId !== null) { + $filter = array_merge($filter, [ + 'PROVIDER_ID' => 'IMOPENLINES_SESSION', + 'PROVIDER_TYPE_ID' => $openLineTypeId, + ]); + } else { + $filter = array_merge($filter, ['PROVIDER_ID' => 'IMOPENLINES_SESSION']); + } + + foreach ($this->bulkItemsReader->getTraversableList('crm.activity.list', $order, $filter, $select, $limit) as $cnt => $item) { + yield $cnt => new OpenLineActivityItemResult($item); + } + } +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/ReadModel/VoximplantFetcher.php b/src/Services/CRM/Activity/ReadModel/VoximplantFetcher.php new file mode 100644 index 00000000..1ed02368 --- /dev/null +++ b/src/Services/CRM/Activity/ReadModel/VoximplantFetcher.php @@ -0,0 +1,44 @@ +bulkItemsReader = $bulkItemsReader; + } + + /** + * @param array $order + * @param array $filter + * @param array $select + * @param int|null $limit + * + * @return \Bitrix24\SDK\Services\CRM\Activity\Result\ActivityItemResult[]|Generator + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function getList(array $order, array $filter, array $select, ?int $limit = null): Generator + { + $filter = array_merge($filter, [ + 'PROVIDER_ID' => 'VOXIMPLANT_CALL', + 'PROVIDER_TYPE_ID' => 'CALL', + ]); + + foreach ($this->bulkItemsReader->getTraversableList('crm.activity.list', $order, $filter, $select, $limit) as $cnt => $item) { + yield $cnt => new ActivityItemResult($item); + } + } +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/ReadModel/WebFormFetcher.php b/src/Services/CRM/Activity/ReadModel/WebFormFetcher.php new file mode 100644 index 00000000..5d4c0662 --- /dev/null +++ b/src/Services/CRM/Activity/ReadModel/WebFormFetcher.php @@ -0,0 +1,48 @@ +bulkItemsReader = $bulkItemsReader; + } + + /** + * @param array $order + * @param array $filter + * @param array $select + * @param int|null $webFormId + * @param int|null $limit + * + * @return WebFormActivityItemResult[]|Generator + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function getList(array $order, array $filter, array $select, ?int $webFormId = null, ?int $limit = null): Generator + { + if ($webFormId !== null) { + $filter = array_merge($filter, [ + 'PROVIDER_ID' => 'CRM_WEBFORM', + 'PROVIDER_TYPE_ID' => $webFormId, + ]); + } else { + $filter = array_merge($filter, ['PROVIDER_ID' => 'CRM_WEBFORM']); + } + foreach ($this->bulkItemsReader->getTraversableList('crm.activity.list', $order, $filter, $select, $limit) as $cnt => $item) { + yield $cnt => new WebFormActivityItemResult($item); + } + } +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/Result/ActivityItemResult.php b/src/Services/CRM/Activity/Result/ActivityItemResult.php index d7fecbfb..72062fd8 100644 --- a/src/Services/CRM/Activity/Result/ActivityItemResult.php +++ b/src/Services/CRM/Activity/Result/ActivityItemResult.php @@ -36,13 +36,13 @@ * @property-read string $AUTHOR_ID // Activity author ID * @property-read string $LAST_UPDATED // Date of the last update date * @property-read string $EDITOR_ID // Editor - * @property-read string $SETTINGS + * @property-read array $SETTINGS * @property-read string $ORIGIN_ID * @property-read string $ORIGINATOR_ID * @property-read int $RESULT_STATUS * @property-read int $RESULT_STREAM * @property-read string $RESULT_SOURCE_ID - * @property-read string $PROVIDER_PARAMS + * @property-read array $PROVIDER_PARAMS * @property-read string $PROVIDER_DATA * @property-read int $RESULT_MARK * @property-read string $RESULT_VALUE @@ -50,8 +50,8 @@ * @property-read string $RESULT_CURRENCY_ID * @property-read int $AUTOCOMPLETE_RULE // Autocompletion * @property-read string $BINDINGS // Bindings - * @property-read string $COMMUNICATIONS // type crm_activity_communication - * @property-read string $FILES // Added files with diskfile type + * @property-read array $COMMUNICATIONS // type crm_activity_communication + * @property-read array $FILES // Added files with diskfile type * @property-read string $WEBDAV_ELEMENTS */ class ActivityItemResult extends AbstractCrmItem diff --git a/src/Services/CRM/Activity/Result/Email/EmailActivityItemResult.php b/src/Services/CRM/Activity/Result/Email/EmailActivityItemResult.php new file mode 100644 index 00000000..c3056932 --- /dev/null +++ b/src/Services/CRM/Activity/Result/Email/EmailActivityItemResult.php @@ -0,0 +1,22 @@ +data[$offset]); + } + + return parent::__get($offset); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/Result/Email/EmailMeta.php b/src/Services/CRM/Activity/Result/Email/EmailMeta.php new file mode 100644 index 00000000..939672b8 --- /dev/null +++ b/src/Services/CRM/Activity/Result/Email/EmailMeta.php @@ -0,0 +1,19 @@ +data)) { + return new EmailMeta($this->data[$offset]); + } + + return null; + } + + return parent::__get($offset); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/Result/OpenLine/OpenLineActivityItemResult.php b/src/Services/CRM/Activity/Result/OpenLine/OpenLineActivityItemResult.php new file mode 100644 index 00000000..caa83230 --- /dev/null +++ b/src/Services/CRM/Activity/Result/OpenLine/OpenLineActivityItemResult.php @@ -0,0 +1,18 @@ +PROVIDER_PARAMS['USER_CODE']); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/Result/OpenLine/OpenLineProviderParams.php b/src/Services/CRM/Activity/Result/OpenLine/OpenLineProviderParams.php new file mode 100644 index 00000000..5920829f --- /dev/null +++ b/src/Services/CRM/Activity/Result/OpenLine/OpenLineProviderParams.php @@ -0,0 +1,43 @@ +userCode = $userCode; + } + + /** + * @return string + */ + public function getUserCode(): string + { + return $this->userCode; + } + + /** + * @return int + */ + public function getBitrix24UserId(): int + { + return (int)explode('|', $this->getUserCode())[3]; + } + + /** + * @return string + */ + public function getExternalSystemUserId(): string + { + return explode('|', $this->getUserCode())[2]; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/Result/WebForm/VisitedPageItem.php b/src/Services/CRM/Activity/Result/WebForm/VisitedPageItem.php new file mode 100644 index 00000000..c479f8f7 --- /dev/null +++ b/src/Services/CRM/Activity/Result/WebForm/VisitedPageItem.php @@ -0,0 +1,18 @@ +PROVIDER_PARAMS['FIELDS'], + new WebFormMetadata( + $this->PROVIDER_PARAMS['FORM']['IS_USED_USER_CONSENT'], + $this->PROVIDER_PARAMS['FORM']['AGREEMENTS'], + $this->PROVIDER_PARAMS['FORM']['IP'], + $this->PROVIDER_PARAMS['FORM']['LINK'] + ), + $this->PROVIDER_PARAMS['VISITED_PAGES'], + ); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/Result/WebForm/WebFormFieldItem.php b/src/Services/CRM/Activity/Result/WebForm/WebFormFieldItem.php new file mode 100644 index 00000000..1fc1572e --- /dev/null +++ b/src/Services/CRM/Activity/Result/WebForm/WebFormFieldItem.php @@ -0,0 +1,20 @@ +isUsedUserConsent = $isUsedUserConsent; + $this->agreements = $agreements; + $this->ip = $ip; + $this->link = $link; + } + + /** + * @return bool + */ + public function isUsedUserConsent(): bool + { + return $this->isUsedUserConsent; + } + + /** + * @return array + */ + public function getAgreements(): array + { + return $this->agreements; + } + + /** + * @return string + */ + public function getIp(): string + { + return $this->ip; + } + + /** + * @return string + */ + public function getLink(): string + { + return $this->link; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/Result/WebForm/WebFormProviderParams.php b/src/Services/CRM/Activity/Result/WebForm/WebFormProviderParams.php new file mode 100644 index 00000000..d61998a1 --- /dev/null +++ b/src/Services/CRM/Activity/Result/WebForm/WebFormProviderParams.php @@ -0,0 +1,59 @@ +fields = $fields; + $this->webForm = $webForm; + $this->visitedPages = $visitedPages; + } + + /** + * @return WebFormFieldItem[] + */ + public function getFields(): array + { + $res = []; + foreach ($this->fields as $field) { + $res[] = new WebFormFieldItem($field); + } + + return $res; + } + + /** + * @return \Bitrix24\SDK\Services\CRM\Activity\Result\WebForm\WebFormMetadata + */ + public function getWebForm(): WebFormMetadata + { + return $this->webForm; + } + + /** + * @return VisitedPageItem[] + */ + public function getVisitedPages(): array + { + $res = []; + foreach ($this->visitedPages as $page) { + $res[] = new VisitedPageItem($page); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/CRM/CRMServiceBuilder.php b/src/Services/CRM/CRMServiceBuilder.php index 40a9995e..7bd84b03 100644 --- a/src/Services/CRM/CRMServiceBuilder.php +++ b/src/Services/CRM/CRMServiceBuilder.php @@ -202,4 +202,21 @@ public function activity(): Activity\Service\Activity return $this->serviceCache[__METHOD__]; } + + /** + * @return Activity\ActivityFetcherBuilder + */ + public function activityFetcher(): Activity\ActivityFetcherBuilder + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Activity\ActivityFetcherBuilder( + $this->core, + $this->batch, + $this->bulkItemsReader, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } } \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Activity/ReadModel/EmailFetcherTest.php b/tests/Integration/Services/CRM/Activity/ReadModel/EmailFetcherTest.php new file mode 100644 index 00000000..c8bf7ed9 --- /dev/null +++ b/tests/Integration/Services/CRM/Activity/ReadModel/EmailFetcherTest.php @@ -0,0 +1,40 @@ +emailFetcher->getList(['ID' => 'DESC'], [], ['*', 'COMMUNICATIONS',], 5) as $item) { + $itemsCnt++; +// print(sprintf( +// '%s | %s | %s ', +// $item->PROVIDER_TYPE_ID, +// $item->CREATED, +// $item->SUBJECT, +// ) . PHP_EOL); + } + $this->assertTrue(true); + } + + public function setUp(): void + { + $this->emailFetcher = Fabric::getServiceBuilder()->getCRMScope()->activityFetcher()->emailFetcher(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Activity/ReadModel/OpenLineFetcherTest.php b/tests/Integration/Services/CRM/Activity/ReadModel/OpenLineFetcherTest.php new file mode 100644 index 00000000..10628ad5 --- /dev/null +++ b/tests/Integration/Services/CRM/Activity/ReadModel/OpenLineFetcherTest.php @@ -0,0 +1,40 @@ +openLineFetcher->getList(['ID' => 'DESC'], [], ['*', 'COMMUNICATIONS',], null, 5) as $item) { + $itemsCnt++; +// print(sprintf( +// '%s | %s | %s ', +// $item->PROVIDER_TYPE_ID, +// $item->CREATED, +// $item->SUBJECT, +// ) . PHP_EOL); + } + $this->assertTrue(true); + } + + public function setUp(): void + { + $this->openLineFetcher = Fabric::getServiceBuilder()->getCRMScope()->activityFetcher()->openLineFetcher(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Activity/ReadModel/VoximplantFetcherTest.php b/tests/Integration/Services/CRM/Activity/ReadModel/VoximplantFetcherTest.php new file mode 100644 index 00000000..6ad0af15 --- /dev/null +++ b/tests/Integration/Services/CRM/Activity/ReadModel/VoximplantFetcherTest.php @@ -0,0 +1,41 @@ +voximplantFetcher->getList(['ID' => 'DESC'], [], ['*', 'COMMUNICATIONS',], 5) as $item) { + $itemsCnt++; +// print(sprintf( +// '%s | %s | %s ', +// $item->PROVIDER_TYPE_ID, +// $item->CREATED, +// $item->SUBJECT, +// ) . PHP_EOL); + } + $this->assertTrue(true); + } + + public function setUp(): void + { + $this->voximplantFetcher = Fabric::getServiceBuilder()->getCRMScope()->activityFetcher()->voximplantFetcher(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Activity/ReadModel/WebFormFetcherTest.php b/tests/Integration/Services/CRM/Activity/ReadModel/WebFormFetcherTest.php new file mode 100644 index 00000000..f3a9b942 --- /dev/null +++ b/tests/Integration/Services/CRM/Activity/ReadModel/WebFormFetcherTest.php @@ -0,0 +1,40 @@ +webFormFetcher->getList(['ID' => 'DESC'], [], ['*', 'COMMUNICATIONS',], null, 5) as $item) { + $itemsCnt++; +// print(sprintf( +// '%s | %s | %s ', +// $item->PROVIDER_TYPE_ID, +// $item->CREATED, +// $item->SUBJECT, +// ) . PHP_EOL); + } + $this->assertTrue(true); + } + + public function setUp(): void + { + $this->webFormFetcher = Fabric::getServiceBuilder()->getCRMScope()->activityFetcher()->webFormFetcher(); + } +} \ No newline at end of file From 9f673ab50fb634ce48877884fc9efe05d6cb10df Mon Sep 17 00:00:00 2001 From: kirill Date: Mon, 18 Jul 2022 11:39:48 +0300 Subject: [PATCH 381/647] -edit CallType.php --- src/Services/Telephony/Common/CallType.php | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Services/Telephony/Common/CallType.php b/src/Services/Telephony/Common/CallType.php index 392e3243..103777da 100644 --- a/src/Services/Telephony/Common/CallType.php +++ b/src/Services/Telephony/Common/CallType.php @@ -34,37 +34,37 @@ private function __construct(int $typeCode) } /** - * @return string + * @return self */ - public static function outboundCall(): string + public static function outboundCall(): self { - return self::outboundCall; + return new self(self::OUTBOUND_CALL); } /** - * @return string + * @return self */ - public static function inboundCall(): string + public static function inboundCall(): self { - return self::inboundCall; + return new self( self::INBOUND_CALL); } /** - * @return string + * @return self */ - public static function inboundCallWithRedirection(): string + public static function inboundCallWithRedirection(): self { - return self::inboundCallWithRedirection; + return new self( self::INBOUND_CALL_WITH_REDIRECTION); + } /** * @return self */ - - public static function backCall(): string + public static function backCall(): self { return new self( self::CALLBACK); } From 959d8589c9b4c081100da0ba47d857b5dafb5434 Mon Sep 17 00:00:00 2001 From: kirill Date: Mon, 18 Jul 2022 16:28:37 +0300 Subject: [PATCH 382/647] -add new test for method telephony.externalCall.searchCrmEntities --- ...xternalCallSearchCrmEntitiesItemResult.php | 1 - .../ExternalCallSearchCrmEntitiesResult.php | 7 +- .../Telephony/Service/ExternalCallTest.php | 68 +---------- .../Service/SearchCrmEntitiesTest.php | 115 ++++++++++++++++++ 4 files changed, 125 insertions(+), 66 deletions(-) create mode 100644 tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php diff --git a/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesItemResult.php b/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesItemResult.php index e95b9677..e358fe19 100644 --- a/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesItemResult.php +++ b/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesItemResult.php @@ -10,7 +10,6 @@ * @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 */ diff --git a/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesResult.php b/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesResult.php index d71ffd43..ba20bef3 100644 --- a/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesResult.php +++ b/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesResult.php @@ -9,11 +9,12 @@ class ExternalCallSearchCrmEntitiesResult extends AbstractResult { /** - * @return \Bitrix24\SDK\Services\Telephony\Result\ExternalCallSearchCrmEntitiesItemResult + * @return \Bitrix24\SDK\Services\Telephony\Result\ExternalCallSearchCrmEntitiesItemResult[] * @throws \Bitrix24\SDK\Core\Exceptions\BaseException */ - public function getCrmEntitiesClient(): ExternalCallSearchCrmEntitiesItemResult + + public function getCrmEntitiesClient(): array { - return new ExternalCallSearchCrmEntitiesItemResult($this->getCoreResponse()->getResponseData()->getResult()->getResultData()); + return $this->coreResponse->getResponseData()->getResult()->getResultData(); } } \ No newline at end of file diff --git a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php index 79d9ec31..14d3789f 100644 --- a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php +++ b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php @@ -7,6 +7,7 @@ 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; @@ -24,6 +25,7 @@ class ExternalCallTest extends TestCase protected Lead $leadService; protected ExternalCall $externalCallService; private Main $mainService; + protected Contact $contactService; /** * @throws BaseException @@ -48,7 +50,6 @@ public function testRegisterCall(): void ] ] )->getId(); - $userId = $this->mainService->getCurrentUserProfile()->getUserProfile()->ID; $registerCallResult = $this->externalCallService->registerCall([ 'USER_PHONE_INNER' => '14', @@ -62,7 +63,7 @@ public function testRegisterCall(): void 'SHOW' => 1, 'CALL_LIST_ID' => 1, 'LINE_NUMBER' => $phoneNumber, - 'TYPE' => CallType::inboundCall(), + 'TYPE' => (string)CallType::inboundCall(), ])->getExternalCallRegister(); self::assertTrue((bool)$registerCallResult); @@ -182,7 +183,7 @@ public function testFinish(): void 'CALL_START_DATE' => $callStartDate, 'CRM_CREATE' => 0, 'CRM_SOURCE' => '1', - 'CRM_ENTITY_TYPE' => 'LEAD', + 'CRM_ENTITY_TYPE' => CrmEntityType::lead(), 'CRM_ENTITY_ID' => $leadId, 'SHOW' => 1, 'CALL_LIST_ID' => 1, @@ -245,7 +246,7 @@ public function testAttachRecord(): void 'CALL_START_DATE' => $callStartDate, 'CRM_CREATE' => 0, 'CRM_SOURCE' => '1', - 'CRM_ENTITY_TYPE' => 'LEAD', + 'CRM_ENTITY_TYPE' => CrmEntityType::lead(), 'CRM_ENTITY_ID' => $leadId, 'SHOW' => 1, 'CALL_LIST_ID' => 1, @@ -259,7 +260,7 @@ public function testAttachRecord(): void 'DURATION' => 10, 'COST' => 250, 'COST_CURRENCY' => 'RUB', - 'STATUS_CODE' => 'VI_STATUS_200', + 'STATUS_CODE' => StatusSipCodeInterface::STATUS_OK, 'FAILED_REASON' => '', 'RECORD_URL' => '', 'VOTE' => 5, @@ -270,63 +271,6 @@ public function testAttachRecord(): void self::assertGreaterThan(1, $this->externalCallService->attachRecord($registerCallResult->CALL_ID, $fileName, $this->getFileInBase64())->getFileId()); } - /** - * @throws TransportException - * @throws BaseException - * @throws Exception - * @covers ExternalCall::searchCrmEntities - */ - public function testSearchCrmEntities():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' => '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(); - - - $infoAboutClientResult = $this->externalCallService->searchCrmEntities($phoneNumber)->getCrmEntitiesClient(); - self::assertNotEmpty($phoneNumber); - self::assertTrue((bool)$infoAboutClientResult); - } - /** * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException */ diff --git a/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php b/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php new file mode 100644 index 00000000..d563ac40 --- /dev/null +++ b/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php @@ -0,0 +1,115 @@ +format(DateTimeInterface::ATOM); + $phoneNumber = sprintf('+7%s', time()); + $contactId = $this->contactService->add( + [ + 'TITLE' => 'test contact', + 'PHONE' => [ + [ + 'VALUE' => $phoneNumber, + 'VALUE_TYPE' => 'WORK' + ] + ] + ] + )->getId(); + $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' => CrmEntityType::contact(), + 'CRM_ENTITY_ID' => $contactId, + '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(); + + $infoAboutClientThatIsNot = $this->externalCallService->searchCrmEntities($unusedPhone)->getCrmEntitiesClient(); + self::assertEmpty($infoAboutClientThatIsNot); + + $infoAboutClientLeadResult = $this->externalCallService->searchCrmEntities($phoneNumber)->getCrmEntitiesClient(); + $typeName = $infoAboutClientLeadResult[0]['CRM_ENTITY_TYPE']; + self::assertEquals('CONTACT',$typeName,sprintf('name type incorrect, expected: CONTACT , and your type: %s',$typeName)); + //self::assertEquals('LEAD',$typeName,sprintf('name type incorrect, expected: LEAD , and your type: %s',$typeName)); + + self::assertNotEmpty($infoAboutClientLeadResult); + + } + + /** + * @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(); + $this->contactService = Fabric::getServiceBuilder()->getCRMScope()->contact(); + } +} \ No newline at end of file From fc432c074d2a5c3c653ddfb39d314adcf2eeb2a5 Mon Sep 17 00:00:00 2001 From: kirill Date: Mon, 18 Jul 2022 17:27:05 +0300 Subject: [PATCH 383/647] -add new service Call and method telephony.call.attachTranscription(not work now) --- .../Result/CallAttachTranscriptionResult.php | 20 ++++ src/Services/Telephony/Service/Call.php | 39 ++++++ .../Telephony/TelephonyServiceBuilder.php | 13 ++ .../Services/Telephony/Service/CallTest.php | 112 ++++++++++++++++++ .../Telephony/Service/ExternalLineTest.php | 2 + 5 files changed, 186 insertions(+) create mode 100644 src/Services/Telephony/Result/CallAttachTranscriptionResult.php create mode 100644 src/Services/Telephony/Service/Call.php create mode 100644 tests/Integration/Services/Telephony/Service/CallTest.php diff --git a/src/Services/Telephony/Result/CallAttachTranscriptionResult.php b/src/Services/Telephony/Result/CallAttachTranscriptionResult.php new file mode 100644 index 00000000..5e298336 --- /dev/null +++ b/src/Services/Telephony/Result/CallAttachTranscriptionResult.php @@ -0,0 +1,20 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData()['TRANSCRIPT_ID']; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Service/Call.php b/src/Services/Telephony/Service/Call.php new file mode 100644 index 00000000..87d70a53 --- /dev/null +++ b/src/Services/Telephony/Service/Call.php @@ -0,0 +1,39 @@ +core->call( + 'telephony.call.attachTranscription', + [ + 'CALL_ID' => $call_id, + 'COST'=> $cost, + 'COST_CURRENCY'=>$cost_currency, + 'MESSAGE'=>$messages, + ] + ) + ); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/TelephonyServiceBuilder.php b/src/Services/Telephony/TelephonyServiceBuilder.php index 72660f4c..ebe640db 100644 --- a/src/Services/Telephony/TelephonyServiceBuilder.php +++ b/src/Services/Telephony/TelephonyServiceBuilder.php @@ -4,6 +4,7 @@ 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; @@ -34,4 +35,16 @@ public function externalCall(): ExternalCall return $this->serviceCache[__METHOD__]; } + /** + * @return Call + */ + public function call(): Call + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Call($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + } \ No newline at end of file diff --git a/tests/Integration/Services/Telephony/Service/CallTest.php b/tests/Integration/Services/Telephony/Service/CallTest.php new file mode 100644 index 00000000..189a3e77 --- /dev/null +++ b/tests/Integration/Services/Telephony/Service/CallTest.php @@ -0,0 +1,112 @@ +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' => 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(); + + $message = [ + [ + 'SIDE'=>'User', + 'START_TIME'=>1, + 'STOP_TIME'=>3, + 'MESSAGE'=>'HELLO WORLD' + ], + [ + 'SIDE'=> "Client", + 'START_TIME'=>4, + 'STOP_TIME'=>8, + 'MESSAGE'=>"Здравствуйте, вы продаете пылесосы?" + ] + ]; + var_dump($message); + self::assertTrue((bool)$this->callService->attachTranscription($registerCallResult->CALL_ID, 500, 'RUB',$message)->getCallTranscription()); + } + + /** + * @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->mainService = Fabric::getServiceBuilder()->getMainScope()->main(); + } + +} \ No newline at end of file diff --git a/tests/Integration/Services/Telephony/Service/ExternalLineTest.php b/tests/Integration/Services/Telephony/Service/ExternalLineTest.php index dfc91af9..146eb2a5 100644 --- a/tests/Integration/Services/Telephony/Service/ExternalLineTest.php +++ b/tests/Integration/Services/Telephony/Service/ExternalLineTest.php @@ -39,6 +39,7 @@ public function testGet(): void /** * @throws BaseException * @throws TransportException + * @throws \Exception * @covers ExternalLine::update */ public function testUpdateExternalLineName(): void @@ -64,6 +65,7 @@ public function testUpdateExternalLineName(): void /** * @throws BaseException * @throws TransportException + * @throws \Exception * @covers ExternalLine::delete */ public function testDelete(): void From 32840aca84426a8417a4c154dd50e406da0ad5ef Mon Sep 17 00:00:00 2001 From: kirill Date: Mon, 18 Jul 2022 17:29:35 +0300 Subject: [PATCH 384/647] -edit docs --- docs/RU/how-to-add-new-scope/new-scope.md | 68 +++++++++++++++++++++-- 1 file changed, 64 insertions(+), 4 deletions(-) diff --git a/docs/RU/how-to-add-new-scope/new-scope.md b/docs/RU/how-to-add-new-scope/new-scope.md index 4acc8132..c1b9283a 100644 --- a/docs/RU/how-to-add-new-scope/new-scope.md +++ b/docs/RU/how-to-add-new-scope/new-scope.md @@ -8,8 +8,68 @@ 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 будут размещены сервисы с их методами. - 3. В папке Result будут размещены результаты наших методов(то что они будут возвращать). - 4. Также в папке `src/Services/Telephony` размещаем TelephonyServiceBuilder.php. Этот сервис нужен для подключения нашего скоупа с тестами. + 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/Telephony` размещаем TelephonyServiceBuilder.php. Этот сервис нужен для подключения нашего скоупа с тестами. 6. После того как мы добавили наши методы для работы с Телефонией нужно их затестить. Создадим в папке `tests/Integration/Services/Telephony/Service/` наши тесты и проверим все ли работает как надо ExternalLineTest.php. \ No newline at end of file From be99f74c940856a2ae845e25c38a30d3eccbf233 Mon Sep 17 00:00:00 2001 From: kirill Date: Tue, 19 Jul 2022 13:12:41 +0300 Subject: [PATCH 385/647] -add enum CurrencyList -update attachTranscription -edit constant in enum --- .../Telephony/Common/CrmEntityType.php | 18 ++-- .../Telephony/Common/CurrencyList.php | 86 +++++++++++++++++++ .../Common/StatusSipRegistrations.php | 24 +++--- src/Services/Telephony/Common/TypeAtc.php | 12 +-- src/Services/Telephony/Service/Call.php | 2 +- .../Services/Telephony/Service/CallTest.php | 55 ++++++++---- .../Telephony/Service/ExternalCallTest.php | 7 +- .../Service/SearchCrmEntitiesTest.php | 9 +- 8 files changed, 158 insertions(+), 55 deletions(-) create mode 100644 src/Services/Telephony/Common/CurrencyList.php diff --git a/src/Services/Telephony/Common/CrmEntityType.php b/src/Services/Telephony/Common/CrmEntityType.php index 4784eaea..a0110890 100644 --- a/src/Services/Telephony/Common/CrmEntityType.php +++ b/src/Services/Telephony/Common/CrmEntityType.php @@ -8,9 +8,9 @@ class CrmEntityType { - private const contact = 'CONTACT'; - private const company = 'COMPANY'; - private const lead = 'LEAD'; + private const CONTACT = 'CONTACT'; + private const COMPANY = 'COMPANY'; + private const LEAD = 'LEAD'; private string $code; /** @@ -20,9 +20,9 @@ class CrmEntityType private function __construct(string $typeCode) { switch ($typeCode) { - case $this::company: - case $this::contact: - case $this::lead: + case $this::COMPANY: + case $this::CONTACT: + case $this::LEAD: $this->code = $typeCode; break; default: @@ -35,7 +35,7 @@ private function __construct(string $typeCode) */ public static function contact(): self { - return new self(self::contact); + return new self(self::CONTACT); } /** @@ -43,7 +43,7 @@ public static function contact(): self */ public static function company(): self { - return new self(self::company); + return new self(self::COMPANY); } /** @@ -51,7 +51,7 @@ public static function company(): self */ public static function lead(): self { - return new self(self::lead); + return new self(self::LEAD); } /** diff --git a/src/Services/Telephony/Common/CurrencyList.php b/src/Services/Telephony/Common/CurrencyList.php new file mode 100644 index 00000000..3a0cfe08 --- /dev/null +++ b/src/Services/Telephony/Common/CurrencyList.php @@ -0,0 +1,86 @@ +code = $typeCode; + break; + default: + throw new InvalidArgumentException(sprintf('unknown currency %s', $typeCode)); + } + } + + /** + * @return self + */ + public static function rub(): self + { + return new self(self::RUB); + } + + /** + * @return self + */ + public static function usd(): self + { + return new self(self::USD); + } + + /** + * @return self + */ + public static function eur(): self + { + return new self(self::EUR); + } + + /** + * @return self + */ + public static function uah(): self + { + return new self(self::UAH); + } + + /** + * @return self + */ + public static function byn(): self + { + return new self(self::BYN); + } + + /** + * @return string + */ + public function __toString(): string + { + return $this->code; + } + + +} \ No newline at end of file diff --git a/src/Services/Telephony/Common/StatusSipRegistrations.php b/src/Services/Telephony/Common/StatusSipRegistrations.php index f4656615..c358041c 100644 --- a/src/Services/Telephony/Common/StatusSipRegistrations.php +++ b/src/Services/Telephony/Common/StatusSipRegistrations.php @@ -8,10 +8,10 @@ class StatusSipRegistrations { - private const success = 'success'; - private const error = 'error'; - private const in_progress = 'in_progress'; - private const wait = 'wait'; + private const SUCCESS = 'success'; + private const ERROR = 'error'; + private const IN_PROGRESS = 'in_progress'; + private const WAIT = 'wait'; private string $code; /** @@ -21,10 +21,10 @@ class StatusSipRegistrations private function __construct(string $typeSip) { switch ($typeSip) { - case $this::success: - case $this::error: - case $this::in_progress: - case $this::wait: + case $this::SUCCESS: + case $this::ERROR: + case $this::IN_PROGRESS: + case $this::WAIT: $this->code = $typeSip; break; default: @@ -37,7 +37,7 @@ private function __construct(string $typeSip) */ public static function success(): self { - return new self(self::success); + return new self(self::SUCCESS); } /** @@ -45,7 +45,7 @@ public static function success(): self */ public static function error(): self { - return new self(self::error); + return new self(self::ERROR); } /** @@ -53,7 +53,7 @@ public static function error(): self */ public static function in_progress(): self { - return new self(self::in_progress); + return new self(self::IN_PROGRESS); } /** @@ -61,7 +61,7 @@ public static function in_progress(): self */ public static function wait(): self { - return new self(self::wait); + return new self(self::WAIT); } /** diff --git a/src/Services/Telephony/Common/TypeAtc.php b/src/Services/Telephony/Common/TypeAtc.php index 6c6f25ca..f94e1000 100644 --- a/src/Services/Telephony/Common/TypeAtc.php +++ b/src/Services/Telephony/Common/TypeAtc.php @@ -6,8 +6,8 @@ class TypeAtc { - private const cloudAtc = 'cloud'; - private const officeAtc = 'office'; + private const CLOUD = 'cloud'; + private const OFFICE = 'office'; private string $code; /** @@ -17,8 +17,8 @@ class TypeAtc private function __construct(string $typeAtc) { switch ($typeAtc) { - case $this::cloudAtc: - case $this::officeAtc: + case $this::CLOUD: + case $this::OFFICE: $this->code = $typeAtc; break; default: @@ -31,7 +31,7 @@ private function __construct(string $typeAtc) */ public static function cloud(): self { - return new self(self::cloudAtc); + return new self(self::CLOUD); } /** @@ -39,7 +39,7 @@ public static function cloud(): self */ public static function office(): self { - return new self(self::officeAtc); + return new self(self::OFFICE); } /** diff --git a/src/Services/Telephony/Service/Call.php b/src/Services/Telephony/Service/Call.php index 87d70a53..5b4abce8 100644 --- a/src/Services/Telephony/Service/Call.php +++ b/src/Services/Telephony/Service/Call.php @@ -31,7 +31,7 @@ public function attachTranscription(string $call_id , float $cost, string $cost_ 'CALL_ID' => $call_id, 'COST'=> $cost, 'COST_CURRENCY'=>$cost_currency, - 'MESSAGE'=>$messages, + 'MESSAGES'=>$messages, ] ) ); diff --git a/tests/Integration/Services/Telephony/Service/CallTest.php b/tests/Integration/Services/Telephony/Service/CallTest.php index 189a3e77..f1b3f7e3 100644 --- a/tests/Integration/Services/Telephony/Service/CallTest.php +++ b/tests/Integration/Services/Telephony/Service/CallTest.php @@ -3,13 +3,13 @@ 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\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\CurrencyList; use Bitrix24\SDK\Services\Telephony\Common\StatusSipCodeInterface; use Bitrix24\SDK\Services\Telephony\Service\Call; use Bitrix24\SDK\Services\Telephony\Service\ExternalCall; @@ -52,6 +52,33 @@ public function testAttachTranscription():void )->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'=>"Здравствуйте, вы продаете пылесосы?" + ], + [ + '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, @@ -64,7 +91,7 @@ public function testAttachTranscription():void 'SHOW' => 1, 'CALL_LIST_ID' => 1, 'LINE_NUMBER' => $phoneNumber, - 'TYPE' => (string)CallType::inboundCall(), + 'TYPE' => (string)CallType::outboundCall(), ])->getExternalCallRegister(); $finishCallResult = $this->externalCallService->finish([ @@ -72,7 +99,7 @@ public function testAttachTranscription():void 'USER_ID' => $userId, 'DURATION' => 255, 'COST' => 250, - 'COST_CURRENCY' => 'RUB', + 'COST_CURRENCY' => (string)CurrencyList::rub(), 'STATUS_CODE' => StatusSipCodeInterface::STATUS_OK, 'FAILED_REASON' => '', 'RECORD_URL' => '', @@ -80,22 +107,12 @@ public function testAttachTranscription():void 'ADD_TO_CHAT' => 1 ])->getExternalCallFinish(); - $message = [ - [ - 'SIDE'=>'User', - 'START_TIME'=>1, - 'STOP_TIME'=>3, - 'MESSAGE'=>'HELLO WORLD' - ], - [ - 'SIDE'=> "Client", - 'START_TIME'=>4, - 'STOP_TIME'=>8, - 'MESSAGE'=>"Здравствуйте, вы продаете пылесосы?" - ] - ]; - var_dump($message); - self::assertTrue((bool)$this->callService->attachTranscription($registerCallResult->CALL_ID, 500, 'RUB',$message)->getCallTranscription()); + $TranscriptionResult = $this->callService->attachTranscription($registerCallResult->CALL_ID, 50, (string)CurrencyList::rub(), $messages)->getCallTranscription(); + if ($messages[0]['SIDE'] === 'User'){ + self::assertEquals('User', $messages[0]['SIDE']); + } + self::assertGreaterThan(1,$TranscriptionResult); + self::assertNotEmpty($messages); } /** diff --git a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php index 14d3789f..eb28559a 100644 --- a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php +++ b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php @@ -12,6 +12,7 @@ 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\CurrencyList; use Bitrix24\SDK\Services\Telephony\Common\StatusSipCodeInterface; use Bitrix24\SDK\Services\Telephony\Service\ExternalCall; use Bitrix24\SDK\Tests\Integration\Fabric; @@ -196,7 +197,7 @@ public function testFinish(): void 'USER_ID' => $userId, 'DURATION' => 255, 'COST' => 250, - 'COST_CURRENCY' => 'RUB', + 'COST_CURRENCY' => CurrencyList::rub(), 'STATUS_CODE' => StatusSipCodeInterface::STATUS_OK, 'FAILED_REASON' => '', 'RECORD_URL' => '', @@ -259,7 +260,7 @@ public function testAttachRecord(): void 'USER_ID' => $userId, 'DURATION' => 10, 'COST' => 250, - 'COST_CURRENCY' => 'RUB', + 'COST_CURRENCY' => CurrencyList::rub(), 'STATUS_CODE' => StatusSipCodeInterface::STATUS_OK, 'FAILED_REASON' => '', 'RECORD_URL' => '', @@ -284,7 +285,7 @@ public function setUp(): void private function getFileInBase64(): string { - $filePath = __DIR__ . '/TestFile/'; + $filePath = __DIR__ . '/voice/'; $fileName = 'test-phone-record.mp3'; $resBase64 = ''; $handle = fopen($filePath . $fileName, "rb"); diff --git a/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php b/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php index d563ac40..b1a9c63d 100644 --- a/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php +++ b/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php @@ -69,7 +69,7 @@ public function testSearchCrmEntities():void 'CALL_START_DATE' => $callStartDate, 'CRM_CREATE' => 0, 'CRM_SOURCE' => '1', - 'CRM_ENTITY_TYPE' => CrmEntityType::contact(), + 'CRM_ENTITY_TYPE' => CrmEntityType::lead(), 'CRM_ENTITY_ID' => $contactId, 'SHOW' => 1, 'CALL_LIST_ID' => 1, @@ -94,12 +94,10 @@ public function testSearchCrmEntities():void self::assertEmpty($infoAboutClientThatIsNot); $infoAboutClientLeadResult = $this->externalCallService->searchCrmEntities($phoneNumber)->getCrmEntitiesClient(); + self::assertNotEmpty($infoAboutClientLeadResult); $typeName = $infoAboutClientLeadResult[0]['CRM_ENTITY_TYPE']; self::assertEquals('CONTACT',$typeName,sprintf('name type incorrect, expected: CONTACT , and your type: %s',$typeName)); - //self::assertEquals('LEAD',$typeName,sprintf('name type incorrect, expected: LEAD , and your type: %s',$typeName)); - - self::assertNotEmpty($infoAboutClientLeadResult); - + //self::assertEquals('LEAD',$typeName,sprintf('name type incorrect, expected: LEAD , and your type: %s',$typeName)); } /** @@ -112,4 +110,5 @@ public function setUp(): void $this->mainService = Fabric::getServiceBuilder()->getMainScope()->main(); $this->contactService = Fabric::getServiceBuilder()->getCRMScope()->contact(); } + } \ No newline at end of file From f410e7a45f70ba8a713a546b1339575239ad8b53 Mon Sep 17 00:00:00 2001 From: kirill Date: Tue, 19 Jul 2022 14:07:07 +0300 Subject: [PATCH 386/647] -add type casting --- .../Services/Telephony/Service/CallTest.php | 2 +- .../Telephony/Service/ExternalCallTest.php | 14 +++++++------- .../Telephony/Service/SearchCrmEntitiesTest.php | 5 +++-- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/tests/Integration/Services/Telephony/Service/CallTest.php b/tests/Integration/Services/Telephony/Service/CallTest.php index f1b3f7e3..7cfe7c76 100644 --- a/tests/Integration/Services/Telephony/Service/CallTest.php +++ b/tests/Integration/Services/Telephony/Service/CallTest.php @@ -86,7 +86,7 @@ public function testAttachTranscription():void 'CALL_START_DATE' => $callStartDate, 'CRM_CREATE' => 0, 'CRM_SOURCE' => '1', - 'CRM_ENTITY_TYPE' => CrmEntityType::lead(), + 'CRM_ENTITY_TYPE' => (string)CrmEntityType::lead(), 'CRM_ENTITY_ID' => $leadId, 'SHOW' => 1, 'CALL_LIST_ID' => 1, diff --git a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php index eb28559a..414d87f4 100644 --- a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php +++ b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php @@ -59,7 +59,7 @@ public function testRegisterCall(): void 'CALL_START_DATE' => $callStartDate, 'CRM_CREATE' => 0, 'CRM_SOURCE' => '1', - 'CRM_ENTITY_TYPE' => CrmEntityType::lead(), + 'CRM_ENTITY_TYPE' => (string)CrmEntityType::lead(), 'CRM_ENTITY_ID' => $leadId, 'SHOW' => 1, 'CALL_LIST_ID' => 1, @@ -104,7 +104,7 @@ public function testShowCallCard(): void 'CALL_START_DATE' => $callStartDate, 'CRM_CREATE' => 0, 'CRM_SOURCE' => '1', - 'CRM_ENTITY_TYPE' => CrmEntityType::lead(), + 'CRM_ENTITY_TYPE' => (string)CrmEntityType::lead(), 'CRM_ENTITY_ID' => $leadId, 'SHOW' => 0, 'CALL_LIST_ID' => 1, @@ -144,7 +144,7 @@ public function testHideCallCard(): void 'CALL_START_DATE' => $callStartDate, 'CRM_CREATE' => 0, 'CRM_SOURCE' => '1', - 'CRM_ENTITY_TYPE' => CrmEntityType::lead(), + 'CRM_ENTITY_TYPE' => (string)CrmEntityType::lead(), 'CRM_ENTITY_ID' => $leadId, 'SHOW' => 0, 'CALL_LIST_ID' => 1, @@ -184,7 +184,7 @@ public function testFinish(): void 'CALL_START_DATE' => $callStartDate, 'CRM_CREATE' => 0, 'CRM_SOURCE' => '1', - 'CRM_ENTITY_TYPE' => CrmEntityType::lead(), + 'CRM_ENTITY_TYPE' => (string)CrmEntityType::lead(), 'CRM_ENTITY_ID' => $leadId, 'SHOW' => 1, 'CALL_LIST_ID' => 1, @@ -197,7 +197,7 @@ public function testFinish(): void 'USER_ID' => $userId, 'DURATION' => 255, 'COST' => 250, - 'COST_CURRENCY' => CurrencyList::rub(), + 'COST_CURRENCY' => (string)CurrencyList::rub(), 'STATUS_CODE' => StatusSipCodeInterface::STATUS_OK, 'FAILED_REASON' => '', 'RECORD_URL' => '', @@ -247,7 +247,7 @@ public function testAttachRecord(): void 'CALL_START_DATE' => $callStartDate, 'CRM_CREATE' => 0, 'CRM_SOURCE' => '1', - 'CRM_ENTITY_TYPE' => CrmEntityType::lead(), + 'CRM_ENTITY_TYPE' => (string)CrmEntityType::lead(), 'CRM_ENTITY_ID' => $leadId, 'SHOW' => 1, 'CALL_LIST_ID' => 1, @@ -260,7 +260,7 @@ public function testAttachRecord(): void 'USER_ID' => $userId, 'DURATION' => 10, 'COST' => 250, - 'COST_CURRENCY' => CurrencyList::rub(), + 'COST_CURRENCY' => (string)CurrencyList::rub(), 'STATUS_CODE' => StatusSipCodeInterface::STATUS_OK, 'FAILED_REASON' => '', 'RECORD_URL' => '', diff --git a/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php b/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php index b1a9c63d..e24d6938 100644 --- a/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php +++ b/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php @@ -11,6 +11,7 @@ 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\CurrencyList; use Bitrix24\SDK\Services\Telephony\Common\StatusSipCodeInterface; use Bitrix24\SDK\Services\Telephony\Service\ExternalCall; use Bitrix24\SDK\Tests\Integration\Fabric; @@ -69,7 +70,7 @@ public function testSearchCrmEntities():void 'CALL_START_DATE' => $callStartDate, 'CRM_CREATE' => 0, 'CRM_SOURCE' => '1', - 'CRM_ENTITY_TYPE' => CrmEntityType::lead(), + 'CRM_ENTITY_TYPE' => (string)CrmEntityType::lead(), 'CRM_ENTITY_ID' => $contactId, 'SHOW' => 1, 'CALL_LIST_ID' => 1, @@ -82,7 +83,7 @@ public function testSearchCrmEntities():void 'USER_ID' => $userId, 'DURATION' => 255, 'COST' => 250, - 'COST_CURRENCY' => 'RUB', + 'COST_CURRENCY' => (string)CurrencyList::rub(), 'STATUS_CODE' => StatusSipCodeInterface::STATUS_OK, 'FAILED_REASON' => '', 'RECORD_URL' => '', From d3fdfbca93df8d5857ea862635db973697e853f2 Mon Sep 17 00:00:00 2001 From: kirill Date: Tue, 19 Jul 2022 17:28:18 +0300 Subject: [PATCH 387/647] -edit docs --- docs/RU/Application/new-local-application.md | 11 +++--- docs/RU/how-to-add-new-scope/new-scope.md | 39 +++++++++++++++++++- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/docs/RU/Application/new-local-application.md b/docs/RU/Application/new-local-application.md index 9116e620..393a65a3 100644 --- a/docs/RU/Application/new-local-application.md +++ b/docs/RU/Application/new-local-application.md @@ -14,11 +14,10 @@ php -S 127.0.0.1:8080 ngrok http 127.0.0.1:8080 ``` 4. После запуска ngrok будет выдан временный публичный адрес типо `https://7949-178-34-183-66.eu.ngrok.io`, который после выключения сервиса перестанет существовать. Этот адрес исчезнет после завершения ngrok. -5. -1.Зарегистрируйте новый портал битрикс 24. -5. Включите тестовый период для маркет плейса и тарифного плана. -6. Открой портал и перейдите в меню. - 1. Откройте левое меню выберите "Разработчикам" +5. Зарегистрируйте новый портал битрикс 24. +6. Включите тестовый период для маркет плейса и тарифного плана. +7. Открой портал и перейдите в меню. + 1. Откройте левое меню, выберите "Разработчикам" 2. Выберите "Другое" 3. Откройте "Локальное приложение" - 4. Зарегестрируйте новое локальное приложение с нужным вам скоупом + 4. Зарегистрируйте новое локальное приложение с нужным вам скоупом. diff --git a/docs/RU/how-to-add-new-scope/new-scope.md b/docs/RU/how-to-add-new-scope/new-scope.md index c1b9283a..d812542e 100644 --- a/docs/RU/how-to-add-new-scope/new-scope.md +++ b/docs/RU/how-to-add-new-scope/new-scope.md @@ -71,5 +71,40 @@ composer install } } - 4. Также в папке `src/Services/Telephony` размещаем TelephonyServiceBuilder.php. Этот сервис нужен для подключения нашего скоупа с тестами. -6. После того как мы добавили наши методы для работы с Телефонией нужно их затестить. Создадим в папке `tests/Integration/Services/Telephony/Service/` наши тесты и проверим все ли работает как надо ExternalLineTest.php. \ No newline at end of file + 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 bf3b1134e03d52f1333f84a62eaaadcd124fa511 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Wed, 20 Jul 2022 13:32:45 +0300 Subject: [PATCH 388/647] -edit header and edit test SearchCrmEntitiesTest.php --- src/Services/Telephony/Common/CallType.php | 9 ++ .../Telephony/Common/CrmEntityType.php | 9 ++ .../Telephony/Common/CurrencyList.php | 9 ++ .../Common/StatusSipCodeInterface.php | 9 ++ .../Common/StatusSipRegistrations.php | 9 ++ src/Services/Telephony/Common/TypeAtc.php | 11 ++ .../Result/CallAttachTranscriptionResult.php | 9 ++ .../Result/ExternalCallFinishItemResult.php | 9 ++ .../Result/ExternalCallFinishResult.php | 9 ++ .../Result/ExternalCallHideResult.php | 9 ++ .../Result/ExternalCallRecordResult.php | 9 ++ .../Result/ExternalCallRegisterItemResult.php | 9 ++ .../Result/ExternalCallRegisterResult.php | 9 ++ ...xternalCallSearchCrmEntitiesItemResult.php | 10 ++ .../ExternalCallSearchCrmEntitiesResult.php | 20 ++- .../Result/ExternalCallShowResult.php | 9 ++ .../Result/ExternalLineAddResult.php | 9 ++ .../Result/ExternalLineDeleteResult.php | 9 ++ .../Result/ExternalLineItemResult.php | 9 ++ .../Result/ExternalLineUpdateResult.php | 9 ++ .../Telephony/Result/ExternalLinesResult.php | 9 ++ src/Services/Telephony/Service/Call.php | 9 ++ .../Telephony/Service/ExternalCall.php | 9 ++ .../Telephony/Service/ExternalLine.php | 9 ++ .../Telephony/TelephonyServiceBuilder.php | 11 +- .../Services/Telephony/Service/CallTest.php | 35 +++-- .../Telephony/Service/ExternalCallTest.php | 11 +- .../Telephony/Service/ExternalLineTest.php | 9 ++ .../Service/SearchCrmEntitiesTest.php | 125 +++++++++++------- 29 files changed, 356 insertions(+), 65 deletions(-) diff --git a/src/Services/Telephony/Common/CallType.php b/src/Services/Telephony/Common/CallType.php index 103777da..30ac1ce3 100644 --- a/src/Services/Telephony/Common/CallType.php +++ b/src/Services/Telephony/Common/CallType.php @@ -2,6 +2,15 @@ declare(strict_types=1); +/* + * This file is part of the bitrix24-php-sdk package. + * + * Kirill Кhramov + * + * 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; diff --git a/src/Services/Telephony/Common/CrmEntityType.php b/src/Services/Telephony/Common/CrmEntityType.php index a0110890..de25f725 100644 --- a/src/Services/Telephony/Common/CrmEntityType.php +++ b/src/Services/Telephony/Common/CrmEntityType.php @@ -2,6 +2,15 @@ declare(strict_types=1); +/* + * This file is part of the bitrix24-php-sdk package. + * + * Kirill Кhramov + * + * 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; diff --git a/src/Services/Telephony/Common/CurrencyList.php b/src/Services/Telephony/Common/CurrencyList.php index 3a0cfe08..fe9c7411 100644 --- a/src/Services/Telephony/Common/CurrencyList.php +++ b/src/Services/Telephony/Common/CurrencyList.php @@ -2,6 +2,15 @@ declare(strict_types=1); +/* + * This file is part of the bitrix24-php-sdk package. + * + * Kirill Кhramov + * + * 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; diff --git a/src/Services/Telephony/Common/StatusSipCodeInterface.php b/src/Services/Telephony/Common/StatusSipCodeInterface.php index 97499f35..dc21a2ed 100644 --- a/src/Services/Telephony/Common/StatusSipCodeInterface.php +++ b/src/Services/Telephony/Common/StatusSipCodeInterface.php @@ -2,6 +2,15 @@ declare(strict_types=1); +/* + * This file is part of the bitrix24-php-sdk package. + * + * Kirill Кhramov + * + * 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 diff --git a/src/Services/Telephony/Common/StatusSipRegistrations.php b/src/Services/Telephony/Common/StatusSipRegistrations.php index c358041c..6c2984c2 100644 --- a/src/Services/Telephony/Common/StatusSipRegistrations.php +++ b/src/Services/Telephony/Common/StatusSipRegistrations.php @@ -2,6 +2,15 @@ declare(strict_types=1); +/* + * This file is part of the bitrix24-php-sdk package. + * + * Kirill Кhramov + * + * 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; diff --git a/src/Services/Telephony/Common/TypeAtc.php b/src/Services/Telephony/Common/TypeAtc.php index f94e1000..af0ad7bb 100644 --- a/src/Services/Telephony/Common/TypeAtc.php +++ b/src/Services/Telephony/Common/TypeAtc.php @@ -1,5 +1,16 @@ + * + * 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; diff --git a/src/Services/Telephony/Result/CallAttachTranscriptionResult.php b/src/Services/Telephony/Result/CallAttachTranscriptionResult.php index 5e298336..6d712fad 100644 --- a/src/Services/Telephony/Result/CallAttachTranscriptionResult.php +++ b/src/Services/Telephony/Result/CallAttachTranscriptionResult.php @@ -1,6 +1,15 @@ + * + * 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; diff --git a/src/Services/Telephony/Result/ExternalCallFinishItemResult.php b/src/Services/Telephony/Result/ExternalCallFinishItemResult.php index d49a0e15..4057a89d 100644 --- a/src/Services/Telephony/Result/ExternalCallFinishItemResult.php +++ b/src/Services/Telephony/Result/ExternalCallFinishItemResult.php @@ -2,6 +2,15 @@ declare(strict_types=1); +/* + * This file is part of the bitrix24-php-sdk package. + * + * Kirill Кhramov + * + * 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; diff --git a/src/Services/Telephony/Result/ExternalCallFinishResult.php b/src/Services/Telephony/Result/ExternalCallFinishResult.php index bebb8be8..d552dd6e 100644 --- a/src/Services/Telephony/Result/ExternalCallFinishResult.php +++ b/src/Services/Telephony/Result/ExternalCallFinishResult.php @@ -2,6 +2,15 @@ declare(strict_types=1); +/* + * This file is part of the bitrix24-php-sdk package. + * + * Kirill Кhramov + * + * 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; diff --git a/src/Services/Telephony/Result/ExternalCallHideResult.php b/src/Services/Telephony/Result/ExternalCallHideResult.php index 102b72a5..5f9df65b 100644 --- a/src/Services/Telephony/Result/ExternalCallHideResult.php +++ b/src/Services/Telephony/Result/ExternalCallHideResult.php @@ -2,6 +2,15 @@ declare(strict_types=1); +/* + * This file is part of the bitrix24-php-sdk package. + * + * Kirill Кhramov + * + * 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; diff --git a/src/Services/Telephony/Result/ExternalCallRecordResult.php b/src/Services/Telephony/Result/ExternalCallRecordResult.php index d059d448..3e7aeafb 100644 --- a/src/Services/Telephony/Result/ExternalCallRecordResult.php +++ b/src/Services/Telephony/Result/ExternalCallRecordResult.php @@ -1,6 +1,15 @@ + * + * 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; diff --git a/src/Services/Telephony/Result/ExternalCallRegisterItemResult.php b/src/Services/Telephony/Result/ExternalCallRegisterItemResult.php index 84f82666..ba8a09c2 100644 --- a/src/Services/Telephony/Result/ExternalCallRegisterItemResult.php +++ b/src/Services/Telephony/Result/ExternalCallRegisterItemResult.php @@ -2,6 +2,15 @@ declare(strict_types=1); +/* + * This file is part of the bitrix24-php-sdk package. + * + * Kirill Кhramov + * + * 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; diff --git a/src/Services/Telephony/Result/ExternalCallRegisterResult.php b/src/Services/Telephony/Result/ExternalCallRegisterResult.php index 4ab2b045..7610d80d 100644 --- a/src/Services/Telephony/Result/ExternalCallRegisterResult.php +++ b/src/Services/Telephony/Result/ExternalCallRegisterResult.php @@ -2,6 +2,15 @@ declare(strict_types=1); +/* + * This file is part of the bitrix24-php-sdk package. + * + * Kirill Кhramov + * + * 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; diff --git a/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesItemResult.php b/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesItemResult.php index e358fe19..891ef5c2 100644 --- a/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesItemResult.php +++ b/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesItemResult.php @@ -2,6 +2,15 @@ declare(strict_types=1); +/* + * This file is part of the bitrix24-php-sdk package. + * + * Kirill Кhramov + * + * 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; @@ -10,6 +19,7 @@ * @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 */ diff --git a/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesResult.php b/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesResult.php index ba20bef3..e5926ffa 100644 --- a/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesResult.php +++ b/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesResult.php @@ -2,6 +2,15 @@ declare(strict_types=1); +/* + * This file is part of the bitrix24-php-sdk package. + * + * Kirill Кhramov + * + * 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; @@ -9,12 +18,17 @@ class ExternalCallSearchCrmEntitiesResult extends AbstractResult { /** - * @return \Bitrix24\SDK\Services\Telephony\Result\ExternalCallSearchCrmEntitiesItemResult[] + * @return array * @throws \Bitrix24\SDK\Core\Exceptions\BaseException */ - public function getCrmEntitiesClient(): array + public function getCrmEntities():array { - return $this->coreResponse->getResponseData()->getResult()->getResultData(); + $res = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { + $res[] = $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 index a8aa1fd3..2b73f185 100644 --- a/src/Services/Telephony/Result/ExternalCallShowResult.php +++ b/src/Services/Telephony/Result/ExternalCallShowResult.php @@ -2,6 +2,15 @@ declare(strict_types=1); +/* + * This file is part of the bitrix24-php-sdk package. + * + * Kirill Кhramov + * + * 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; diff --git a/src/Services/Telephony/Result/ExternalLineAddResult.php b/src/Services/Telephony/Result/ExternalLineAddResult.php index 8542bf7a..1b1f6f54 100644 --- a/src/Services/Telephony/Result/ExternalLineAddResult.php +++ b/src/Services/Telephony/Result/ExternalLineAddResult.php @@ -2,6 +2,15 @@ declare(strict_types=1); +/* + * This file is part of the bitrix24-php-sdk package. + * + * Kirill Кhramov + * + * 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; diff --git a/src/Services/Telephony/Result/ExternalLineDeleteResult.php b/src/Services/Telephony/Result/ExternalLineDeleteResult.php index b780c507..f8f0d570 100644 --- a/src/Services/Telephony/Result/ExternalLineDeleteResult.php +++ b/src/Services/Telephony/Result/ExternalLineDeleteResult.php @@ -2,6 +2,15 @@ declare(strict_types=1); +/* + * This file is part of the bitrix24-php-sdk package. + * + * Kirill Кhramov + * + * 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; diff --git a/src/Services/Telephony/Result/ExternalLineItemResult.php b/src/Services/Telephony/Result/ExternalLineItemResult.php index 8edf51f3..426039d6 100644 --- a/src/Services/Telephony/Result/ExternalLineItemResult.php +++ b/src/Services/Telephony/Result/ExternalLineItemResult.php @@ -2,6 +2,15 @@ declare(strict_types=1); +/* + * This file is part of the bitrix24-php-sdk package. + * + * Kirill Кhramov + * + * 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; diff --git a/src/Services/Telephony/Result/ExternalLineUpdateResult.php b/src/Services/Telephony/Result/ExternalLineUpdateResult.php index 2b3647bc..6eed88f8 100644 --- a/src/Services/Telephony/Result/ExternalLineUpdateResult.php +++ b/src/Services/Telephony/Result/ExternalLineUpdateResult.php @@ -2,6 +2,15 @@ declare(strict_types=1); +/* + * This file is part of the bitrix24-php-sdk package. + * + * Kirill Кhramov + * + * 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; diff --git a/src/Services/Telephony/Result/ExternalLinesResult.php b/src/Services/Telephony/Result/ExternalLinesResult.php index d1c6ea8e..eee79926 100644 --- a/src/Services/Telephony/Result/ExternalLinesResult.php +++ b/src/Services/Telephony/Result/ExternalLinesResult.php @@ -1,6 +1,15 @@ + * + * 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; diff --git a/src/Services/Telephony/Service/Call.php b/src/Services/Telephony/Service/Call.php index 5b4abce8..6abac517 100644 --- a/src/Services/Telephony/Service/Call.php +++ b/src/Services/Telephony/Service/Call.php @@ -2,6 +2,15 @@ declare(strict_types=1); +/* + * This file is part of the bitrix24-php-sdk package. + * + * Kirill Кhramov + * + * 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; diff --git a/src/Services/Telephony/Service/ExternalCall.php b/src/Services/Telephony/Service/ExternalCall.php index d020a0c6..b4f67c6e 100644 --- a/src/Services/Telephony/Service/ExternalCall.php +++ b/src/Services/Telephony/Service/ExternalCall.php @@ -2,6 +2,15 @@ declare(strict_types=1); +/* + * This file is part of the bitrix24-php-sdk package. + * + * Kirill Кhramov + * + * 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; diff --git a/src/Services/Telephony/Service/ExternalLine.php b/src/Services/Telephony/Service/ExternalLine.php index c1427b9d..86c5b636 100644 --- a/src/Services/Telephony/Service/ExternalLine.php +++ b/src/Services/Telephony/Service/ExternalLine.php @@ -2,6 +2,15 @@ declare(strict_types=1); +/* + * This file is part of the bitrix24-php-sdk package. + * + * Kirill Кhramov + * + * 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; diff --git a/src/Services/Telephony/TelephonyServiceBuilder.php b/src/Services/Telephony/TelephonyServiceBuilder.php index ebe640db..1891a0e3 100644 --- a/src/Services/Telephony/TelephonyServiceBuilder.php +++ b/src/Services/Telephony/TelephonyServiceBuilder.php @@ -1,6 +1,15 @@ + * + * 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; @@ -14,7 +23,7 @@ class TelephonyServiceBuilder extends AbstractServiceBuilder /** * @return ExternalLine */ - public function externalline(): ExternalLine + public function externalLine(): ExternalLine { if (!isset($this->serviceCache[__METHOD__])) { $this->serviceCache[__METHOD__] = new ExternalLine($this->core, $this->log); diff --git a/tests/Integration/Services/Telephony/Service/CallTest.php b/tests/Integration/Services/Telephony/Service/CallTest.php index 7cfe7c76..e00ed3c2 100644 --- a/tests/Integration/Services/Telephony/Service/CallTest.php +++ b/tests/Integration/Services/Telephony/Service/CallTest.php @@ -1,10 +1,20 @@ + * + * 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; @@ -25,23 +35,24 @@ class CallTest extends TestCase protected Lead $leadService; protected ExternalCall $externalCallService; protected Main $mainService; + protected Contact $contactService; /** * @throws BaseException * @throws TransportException * @throws Exception - * @covers ExternalCall::attachTranscription + * @covers Call::attachTranscription */ - - public function testAttachTranscription():void + public function testAttachTranscription(): void { $datetime = new DateTime('now'); $callStartDate = $datetime->format(DateTimeInterface::ATOM); $phoneNumber = sprintf('+7%s', time()); - $leadId = $this->leadService->add( + $contactId = $this->contactService->add( [ - 'TITLE' => 'test lead', + 'NAME' => 'Глеб', + 'SECOND_NAME' => 'Егорович', 'PHONE' => [ [ 'VALUE' => $phoneNumber, @@ -68,17 +79,18 @@ public function testAttachTranscription():void ], [ 'SIDE'=>'User', - 'START_TIME'=>1, - 'STOP_TIME'=>3, + 'START_TIME'=>8, + 'STOP_TIME'=>10, 'MESSAGE'=>'HELLO WORLD' ], [ 'SIDE'=> "Client", - 'START_TIME'=>4, - 'STOP_TIME'=>8, + 'START_TIME'=>12, + 'STOP_TIME'=>15, 'MESSAGE'=>"Здравствуйте, вы продаете пылесосы?" ] ]; + $registerCallResult = $this->externalCallService->registerCall([ 'USER_PHONE_INNER' => '14', 'USER_ID' => $userId, @@ -86,8 +98,8 @@ public function testAttachTranscription():void 'CALL_START_DATE' => $callStartDate, 'CRM_CREATE' => 0, 'CRM_SOURCE' => '1', - 'CRM_ENTITY_TYPE' => (string)CrmEntityType::lead(), - 'CRM_ENTITY_ID' => $leadId, + 'CRM_ENTITY_TYPE' => (string)CrmEntityType::contact(), + 'CRM_ENTITY_ID' => $contactId, 'SHOW' => 1, 'CALL_LIST_ID' => 1, 'LINE_NUMBER' => $phoneNumber, @@ -123,6 +135,7 @@ 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(); } diff --git a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php index 414d87f4..08b86031 100644 --- a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php +++ b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php @@ -2,6 +2,15 @@ declare(strict_types=1); +/* + * This file is part of the bitrix24-php-sdk package. + * + * Kirill Кhramov + * + * 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; @@ -285,7 +294,7 @@ public function setUp(): void private function getFileInBase64(): string { - $filePath = __DIR__ . '/voice/'; + $filePath = __DIR__ . '/TestFile/'; $fileName = 'test-phone-record.mp3'; $resBase64 = ''; $handle = fopen($filePath . $fileName, "rb"); diff --git a/tests/Integration/Services/Telephony/Service/ExternalLineTest.php b/tests/Integration/Services/Telephony/Service/ExternalLineTest.php index 146eb2a5..d8320432 100644 --- a/tests/Integration/Services/Telephony/Service/ExternalLineTest.php +++ b/tests/Integration/Services/Telephony/Service/ExternalLineTest.php @@ -2,6 +2,15 @@ declare(strict_types=1); +/* + * This file is part of the bitrix24-php-sdk package. + * + * Kirill Кhramov + * + * 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; diff --git a/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php b/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php index e24d6938..f9230136 100644 --- a/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php +++ b/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php @@ -2,6 +2,15 @@ declare(strict_types=1); +/* + * This file is part of the bitrix24-php-sdk package. + * + * Kirill Кhramov + * + * 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; @@ -20,11 +29,11 @@ use Exception; use PHPUnit\Framework\TestCase; -class SearchCrmEntitiesTest extends TestCase{ +class SearchCrmEntitiesTest extends TestCase +{ protected Lead $leadService; protected ExternalCall $externalCallService; - private Main $mainService; protected Contact $contactService; /** @@ -33,78 +42,96 @@ class SearchCrmEntitiesTest extends TestCase{ * @throws Exception * @covers ExternalCall::searchCrmEntities */ - public function testSearchCrmEntities():void + public function testSearchCrmEntities(): void { - $unusedPhone = sprintf('+8%s', time()); - $datetime = new DateTime('now'); - $callStartDate = $datetime->format(DateTimeInterface::ATOM); - $phoneNumber = sprintf('+7%s', time()); - $contactId = $this->contactService->add( + //Не зарегистрированный телефон + $unusedPhone = '+51045005010'; + $infoAboutNotExistingCustomerResult = $this->externalCallService->searchCrmEntities($unusedPhone)->getCrmEntities(); + self::assertEmpty($infoAboutNotExistingCustomerResult,sprintf('No customers can be found for this number: %s',$unusedPhone)); + + //Зарегистрированный контакт + $phoneNumberClient1 = sprintf('+7%s', time()); + $contactId1 = $this->contactService->add( [ - 'TITLE' => 'test contact', + 'NAME' => 'Глеб', + 'SECOND_NAME' => 'Егорович', 'PHONE' => [ [ - 'VALUE' => $phoneNumber, + 'VALUE' => $phoneNumberClient1, 'VALUE_TYPE' => 'WORK' ] ] ] )->getId(); - $leadId = $this->leadService->add( + $infoAboutClientResult1 = $this->externalCallService->searchCrmEntities($phoneNumberClient1)->getCrmEntities(); + self::assertNotEmpty($infoAboutClientResult1); + $entityType = $infoAboutClientResult1[0]['CRM_ENTITY_TYPE']; + self::assertEquals('CONTACT', $entityType, sprintf('name type incorrect, expected: CONTACT , and your type: %s', $entityType)); + $this->contactService->delete($contactId1)->isSuccess(); + + //Зарегистрированный лид + $phoneNumberLead1 = sprintf('+7%s', time()); + $leadId1 = $this->leadService->add( [ - 'TITLE' => 'test lead', + 'TITLE' => 'ИП Титов', + 'NAME' => 'Кирилл', 'PHONE' => [ [ - 'VALUE' => $phoneNumber, + 'VALUE' => $phoneNumberLead1, 'VALUE_TYPE' => 'WORK' ] ] ] )->getId(); - $userId = $this->mainService->getCurrentUserProfile()->getUserProfile()->ID; + $infoAboutLeadResult = $this->externalCallService->searchCrmEntities($phoneNumberLead1)->getCrmEntities(); + self::assertNotEmpty($infoAboutLeadResult); + $entityType = $infoAboutLeadResult[0]['CRM_ENTITY_TYPE']; + self::assertEquals('LEAD', $entityType, sprintf('name type incorrect, expected: LEAD , and your type: %s', $entityType)); + $this->leadService->delete($leadId1); - $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' => $contactId, - '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' => (string)CurrencyList::rub(), - 'STATUS_CODE' => StatusSipCodeInterface::STATUS_OK, - 'FAILED_REASON' => '', - 'RECORD_URL' => '', - 'VOTE' => 5, - 'ADD_TO_CHAT' => 1 - ])->getExternalCallFinish(); - - $infoAboutClientThatIsNot = $this->externalCallService->searchCrmEntities($unusedPhone)->getCrmEntitiesClient(); - self::assertEmpty($infoAboutClientThatIsNot); + $onePhoneTwoContact = sprintf('+7%s', time()); + $contactId2 = $this->contactService->add( + [ + 'NAME' => 'Глеб', + 'SECOND_NAME' => 'Егорович', + 'PHONE' => [ + [ + 'VALUE' => $onePhoneTwoContact, + 'VALUE_TYPE' => 'WORK' + ] + ] + ] + )->getId(); + $contactId3 = $this->contactService->add( + [ + 'NAME' => 'Хлеб', + 'SECOND_NAME' => 'Олегович', + 'PHONE' => [ + [ + 'VALUE' => $onePhoneTwoContact, + 'VALUE_TYPE' => 'WORK' + ] + ] + ] + )->getId(); + $infoAboutTwoContactResult = $this->externalCallService->searchCrmEntities($onePhoneTwoContact)->getCrmEntities(); + var_dump($infoAboutTwoContactResult); + self::assertNotEmpty($infoAboutTwoContactResult); + $entityTypeContact1 = $infoAboutLeadResult[0]['CRM_ENTITY_TYPE']; + $entityTypeContact2 = $infoAboutLeadResult[1]['CRM_ENTITY_TYPE']; + self::assertEquals('CONTACT', $entityTypeContact1, sprintf('name type incorrect, expected: CONTACT , and your type: %s', $entityTypeContact1)); + self::assertEquals('CONTACT', $entityTypeContact2, sprintf('name type incorrect, expected: CONTACT , and your type: %s', $entityTypeContact2)); + $this->contactService->delete($contactId2); + $this->contactService->delete($contactId3); - $infoAboutClientLeadResult = $this->externalCallService->searchCrmEntities($phoneNumber)->getCrmEntitiesClient(); - self::assertNotEmpty($infoAboutClientLeadResult); - $typeName = $infoAboutClientLeadResult[0]['CRM_ENTITY_TYPE']; - self::assertEquals('CONTACT',$typeName,sprintf('name type incorrect, expected: CONTACT , and your type: %s',$typeName)); - //self::assertEquals('LEAD',$typeName,sprintf('name type incorrect, expected: LEAD , and your type: %s',$typeName)); } /** * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException */ - public function setUp(): void + public + function setUp(): void { $this->externalCallService = Fabric::getServiceBuilder()->getTelephonyScope()->externalCall(); $this->leadService = Fabric::getServiceBuilder()->getCRMScope()->lead(); From 2865dae7b4a870b18455b630d8b1cbe22537f440 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Wed, 20 Jul 2022 18:10:08 +0300 Subject: [PATCH 389/647] -edit composer.json , add library moneyphp. --- composer.json | 7 +++++-- src/Services/Telephony/Service/Call.php | 4 ++-- .../Services/Telephony/Service/CallTest.php | 15 +++++++++++++-- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/composer.json b/composer.json index 0a09205e..465c2fdc 100644 --- a/composer.json +++ b/composer.json @@ -19,6 +19,7 @@ "require": { "php": "7.4.*|8.*", "ext-json": "*", + "ext-bcmath": "*", "ext-curl": "*", "psr/log": "^1.1.4 || ^2.0 || ^3.0", "fig/http-message-util": "1.1.*", @@ -26,7 +27,8 @@ "symfony/http-client-contracts": "^2.5 || ^3.1", "symfony/http-foundation": "5.4.* || 6.*", "symfony/event-dispatcher": "5.4.* || 6.*", - "ramsey/uuid": "^4.2.3" + "ramsey/uuid": "^4.2.3", + "moneyphp/money": "v3.3.1.* || v4.0.4" }, "require-dev": { "monolog/monolog": "2.1.*", @@ -36,7 +38,8 @@ "phpstan/phpstan": "1.*", "phpunit/phpunit": "9.5.*", "symfony/stopwatch": "5.4.* || 6.*", - "roave/security-advisories": "dev-master" + "roave/security-advisories": "dev-master", + "ext-intl": "*" }, "autoload": { "psr-4": { diff --git a/src/Services/Telephony/Service/Call.php b/src/Services/Telephony/Service/Call.php index 6abac517..4f4568b2 100644 --- a/src/Services/Telephony/Service/Call.php +++ b/src/Services/Telephony/Service/Call.php @@ -23,7 +23,7 @@ class Call extends AbstractService * The method adds a call transcript. * * @param string $call_id - * @param float $cost + * @param string $cost * @param string $cost_currency * @param array $messages * @return \Bitrix24\SDK\Services\Telephony\Result\CallAttachTranscriptionResult @@ -31,7 +31,7 @@ class Call extends AbstractService * @throws \Bitrix24\SDK\Core\Exceptions\TransportException * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_call_attachtranscription.php */ - public function attachTranscription(string $call_id , float $cost, string $cost_currency, array $messages): CallAttachTranscriptionResult + public function attachTranscription(string $call_id , string $cost, string $cost_currency, array $messages): CallAttachTranscriptionResult { return new CallAttachTranscriptionResult( $this->core->call( diff --git a/tests/Integration/Services/Telephony/Service/CallTest.php b/tests/Integration/Services/Telephony/Service/CallTest.php index e00ed3c2..9cfee8ad 100644 --- a/tests/Integration/Services/Telephony/Service/CallTest.php +++ b/tests/Integration/Services/Telephony/Service/CallTest.php @@ -27,6 +27,11 @@ 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 @@ -49,6 +54,12 @@ public function testAttachTranscription(): void $datetime = new DateTime('now'); $callStartDate = $datetime->format(DateTimeInterface::ATOM); $phoneNumber = sprintf('+7%s', time()); + $money = new Money(100, new Currency('RUB')); + $currencies = new ISOCurrencies(); + + $moneyFormatter = new DecimalMoneyFormatter($currencies); + + echo $moneyFormatter->format($money); // outputs 1.00 $contactId = $this->contactService->add( [ 'NAME' => 'Глеб', @@ -110,7 +121,7 @@ public function testAttachTranscription(): void 'CALL_ID' => $registerCallResult->CALL_ID, 'USER_ID' => $userId, 'DURATION' => 255, - 'COST' => 250, + 'COST' => $moneyFormatter->format($money), 'COST_CURRENCY' => (string)CurrencyList::rub(), 'STATUS_CODE' => StatusSipCodeInterface::STATUS_OK, 'FAILED_REASON' => '', @@ -119,7 +130,7 @@ public function testAttachTranscription(): void 'ADD_TO_CHAT' => 1 ])->getExternalCallFinish(); - $TranscriptionResult = $this->callService->attachTranscription($registerCallResult->CALL_ID, 50, (string)CurrencyList::rub(), $messages)->getCallTranscription(); + $TranscriptionResult = $this->callService->attachTranscription($registerCallResult->CALL_ID, $moneyFormatter->format($money),(string)CurrencyList::rub(), $messages)->getCallTranscription(); if ($messages[0]['SIDE'] === 'User'){ self::assertEquals('User', $messages[0]['SIDE']); } From 2f62b8812cae94c94007503e1ed5c7de7a0952bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Thu, 21 Jul 2022 11:34:49 +0300 Subject: [PATCH 390/647] -edit test CallTest.php --- composer.json | 2 +- src/Services/AbstractService.php | 6 +- .../Telephony/Common/CurrencyList.php | 95 ------------------- .../Result/CallAttachTranscriptionResult.php | 5 +- src/Services/Telephony/Service/Call.php | 18 ++-- .../Services/Telephony/Service/CallTest.php | 48 ++++------ .../Service/SearchCrmEntitiesTest.php | 2 +- 7 files changed, 36 insertions(+), 140 deletions(-) delete mode 100644 src/Services/Telephony/Common/CurrencyList.php diff --git a/composer.json b/composer.json index 465c2fdc..7a54f0ad 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,7 @@ "symfony/http-foundation": "5.4.* || 6.*", "symfony/event-dispatcher": "5.4.* || 6.*", "ramsey/uuid": "^4.2.3", - "moneyphp/money": "v3.3.1.* || v4.0.4" + "moneyphp/money": "3.* || 4.*" }, "require-dev": { "monolog/monolog": "2.1.*", diff --git a/src/Services/AbstractService.php b/src/Services/AbstractService.php index cf20323f..a2ee2cfa 100644 --- a/src/Services/AbstractService.php +++ b/src/Services/AbstractService.php @@ -5,6 +5,8 @@ namespace Bitrix24\SDK\Services; use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Money\Currencies\ISOCurrencies; +use Money\Formatter\DecimalMoneyFormatter; use Psr\Log\LoggerInterface; /** @@ -19,16 +21,18 @@ abstract class AbstractService */ public CoreInterface $core; protected LoggerInterface $log; + protected DecimalMoneyFormatter $decimalMoneyFormatter; /** * AbstractService constructor. * - * @param CoreInterface $core + * @param CoreInterface $core * @param LoggerInterface $log */ public function __construct(CoreInterface $core, LoggerInterface $log) { $this->core = $core; $this->log = $log; + $this->decimalMoneyFormatter = new DecimalMoneyFormatter(new ISOCurrencies()); } } \ No newline at end of file diff --git a/src/Services/Telephony/Common/CurrencyList.php b/src/Services/Telephony/Common/CurrencyList.php deleted file mode 100644 index fe9c7411..00000000 --- a/src/Services/Telephony/Common/CurrencyList.php +++ /dev/null @@ -1,95 +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 CurrencyList -{ - private const RUB = 'RUB'; - private const USD = 'USD'; - private const EUR = 'EUR'; - private const UAH = 'UAH'; - private const BYN = 'BYN'; - private string $code; - - /** - * @param string $typeCode - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException - */ - private function __construct(string $typeCode) - { - switch ($typeCode) { - case $this::RUB: - case $this::USD: - case $this::EUR: - case $this::UAH: - case $this::BYN: - $this->code = $typeCode; - break; - default: - throw new InvalidArgumentException(sprintf('unknown currency %s', $typeCode)); - } - } - - /** - * @return self - */ - public static function rub(): self - { - return new self(self::RUB); - } - - /** - * @return self - */ - public static function usd(): self - { - return new self(self::USD); - } - - /** - * @return self - */ - public static function eur(): self - { - return new self(self::EUR); - } - - /** - * @return self - */ - public static function uah(): self - { - return new self(self::UAH); - } - - /** - * @return self - */ - public static function byn(): self - { - return new self(self::BYN); - } - - /** - * @return string - */ - public function __toString(): string - { - return $this->code; - } - - -} \ No newline at end of file diff --git a/src/Services/Telephony/Result/CallAttachTranscriptionResult.php b/src/Services/Telephony/Result/CallAttachTranscriptionResult.php index 6d712fad..089049cc 100644 --- a/src/Services/Telephony/Result/CallAttachTranscriptionResult.php +++ b/src/Services/Telephony/Result/CallAttachTranscriptionResult.php @@ -12,17 +12,18 @@ 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 +class CallAttachTranscriptionResult extends AbstractResult implements AddedItemIdResultInterface { /** * @return int * @throws \Bitrix24\SDK\Core\Exceptions\BaseException */ - public function getCallTranscription():int + public function getId():int { return $this->getCoreResponse()->getResponseData()->getResult()->getResultData()['TRANSCRIPT_ID']; } diff --git a/src/Services/Telephony/Service/Call.php b/src/Services/Telephony/Service/Call.php index 4f4568b2..dc64210c 100644 --- a/src/Services/Telephony/Service/Call.php +++ b/src/Services/Telephony/Service/Call.php @@ -15,6 +15,7 @@ use Bitrix24\SDK\Services\AbstractService; use Bitrix24\SDK\Services\Telephony\Result\CallAttachTranscriptionResult; +use Money\Money; class Call extends AbstractService @@ -22,25 +23,24 @@ class Call extends AbstractService /** * The method adds a call transcript. * - * @param string $call_id - * @param string $cost - * @param string $cost_currency - * @param array $messages + * @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 $call_id , string $cost, string $cost_currency, array $messages): CallAttachTranscriptionResult + public function attachTranscription(string $callId, Money $callCosts, array $messages): CallAttachTranscriptionResult { return new CallAttachTranscriptionResult( $this->core->call( 'telephony.call.attachTranscription', [ - 'CALL_ID' => $call_id, - 'COST'=> $cost, - 'COST_CURRENCY'=>$cost_currency, - 'MESSAGES'=>$messages, + 'CALL_ID' => $callId, + 'COST' => $this->decimalMoneyFormatter->format($callCosts), + 'COST_CURRENCY' => $callCosts->getCurrency()->getCode(), + 'MESSAGES' => $messages, ] ) ); diff --git a/tests/Integration/Services/Telephony/Service/CallTest.php b/tests/Integration/Services/Telephony/Service/CallTest.php index 9cfee8ad..202b6e02 100644 --- a/tests/Integration/Services/Telephony/Service/CallTest.php +++ b/tests/Integration/Services/Telephony/Service/CallTest.php @@ -19,7 +19,6 @@ 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\CurrencyList; use Bitrix24\SDK\Services\Telephony\Common\StatusSipCodeInterface; use Bitrix24\SDK\Services\Telephony\Service\Call; use Bitrix24\SDK\Services\Telephony\Service\ExternalCall; @@ -54,7 +53,7 @@ public function testAttachTranscription(): void $datetime = new DateTime('now'); $callStartDate = $datetime->format(DateTimeInterface::ATOM); $phoneNumber = sprintf('+7%s', time()); - $money = new Money(100, new Currency('RUB')); + $callCosts = new Money(1000, new Currency('RUB')); $currencies = new ISOCurrencies(); $moneyFormatter = new DecimalMoneyFormatter($currencies); @@ -77,29 +76,17 @@ public function testAttachTranscription(): void $messages = [ [ - 'SIDE'=>'User', - 'START_TIME'=>1, - 'STOP_TIME'=>3, - 'MESSAGE'=>'HELLO WORLD' + 'SIDE' => 'User', + 'START_TIME' => 1, + 'STOP_TIME' => 3, + 'MESSAGE' => 'HELLO WORLD' ], [ - 'SIDE'=> "Client", - 'START_TIME'=>4, - 'STOP_TIME'=>8, - 'MESSAGE'=>"Здравствуйте, вы продаете пылесосы?" + 'SIDE' => "Client", + 'START_TIME' => 4, + 'STOP_TIME' => 8, + 'MESSAGE' => "Здравствуйте, вы продаете пылесосы?" ], - [ - 'SIDE'=>'User', - 'START_TIME'=>8, - 'STOP_TIME'=>10, - 'MESSAGE'=>'HELLO WORLD' - ], - [ - 'SIDE'=> "Client", - 'START_TIME'=>12, - 'STOP_TIME'=>15, - 'MESSAGE'=>"Здравствуйте, вы продаете пылесосы?" - ] ]; $registerCallResult = $this->externalCallService->registerCall([ @@ -116,13 +103,12 @@ public function testAttachTranscription(): void '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($money), - 'COST_CURRENCY' => (string)CurrencyList::rub(), + 'COST' => $moneyFormatter->format($callCosts), + 'COST_CURRENCY' => $callCosts->getCurrency()->getCode(), 'STATUS_CODE' => StatusSipCodeInterface::STATUS_OK, 'FAILED_REASON' => '', 'RECORD_URL' => '', @@ -130,12 +116,12 @@ public function testAttachTranscription(): void 'ADD_TO_CHAT' => 1 ])->getExternalCallFinish(); - $TranscriptionResult = $this->callService->attachTranscription($registerCallResult->CALL_ID, $moneyFormatter->format($money),(string)CurrencyList::rub(), $messages)->getCallTranscription(); - if ($messages[0]['SIDE'] === 'User'){ - self::assertEquals('User', $messages[0]['SIDE']); - } - self::assertGreaterThan(1,$TranscriptionResult); - self::assertNotEmpty($messages); + self::assertGreaterThan(1, + $this->callService->attachTranscription( + $registerCallResult->CALL_ID, + $callCosts, + $messages)->getId() + ); } /** diff --git a/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php b/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php index f9230136..112e05ec 100644 --- a/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php +++ b/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php @@ -119,7 +119,7 @@ public function testSearchCrmEntities(): void var_dump($infoAboutTwoContactResult); self::assertNotEmpty($infoAboutTwoContactResult); $entityTypeContact1 = $infoAboutLeadResult[0]['CRM_ENTITY_TYPE']; - $entityTypeContact2 = $infoAboutLeadResult[1]['CRM_ENTITY_TYPE']; + $entityTypeContact2 = $infoAboutLeadResult[1]['CRM_ENTITY_TYPE']; self::assertEquals('CONTACT', $entityTypeContact1, sprintf('name type incorrect, expected: CONTACT , and your type: %s', $entityTypeContact1)); self::assertEquals('CONTACT', $entityTypeContact2, sprintf('name type incorrect, expected: CONTACT , and your type: %s', $entityTypeContact2)); $this->contactService->delete($contactId2); From 745b45cb89f62bea9cc2fe9508fcabb2a4cde25b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Thu, 21 Jul 2022 11:35:56 +0300 Subject: [PATCH 391/647] -edit test 2 --- tests/Integration/Services/Telephony/Service/CallTest.php | 2 +- .../Services/Telephony/Service/ExternalCallTest.php | 5 ++--- .../Services/Telephony/Service/SearchCrmEntitiesTest.php | 1 - 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/Integration/Services/Telephony/Service/CallTest.php b/tests/Integration/Services/Telephony/Service/CallTest.php index 202b6e02..1993a385 100644 --- a/tests/Integration/Services/Telephony/Service/CallTest.php +++ b/tests/Integration/Services/Telephony/Service/CallTest.php @@ -58,7 +58,7 @@ public function testAttachTranscription(): void $moneyFormatter = new DecimalMoneyFormatter($currencies); - echo $moneyFormatter->format($money); // outputs 1.00 + $contactId = $this->contactService->add( [ 'NAME' => 'Глеб', diff --git a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php index 08b86031..8a84b595 100644 --- a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php +++ b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php @@ -21,7 +21,6 @@ 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\CurrencyList; use Bitrix24\SDK\Services\Telephony\Common\StatusSipCodeInterface; use Bitrix24\SDK\Services\Telephony\Service\ExternalCall; use Bitrix24\SDK\Tests\Integration\Fabric; @@ -206,7 +205,7 @@ public function testFinish(): void 'USER_ID' => $userId, 'DURATION' => 255, 'COST' => 250, - 'COST_CURRENCY' => (string)CurrencyList::rub(), + 'COST_CURRENCY' => 'RUB', 'STATUS_CODE' => StatusSipCodeInterface::STATUS_OK, 'FAILED_REASON' => '', 'RECORD_URL' => '', @@ -269,7 +268,7 @@ public function testAttachRecord(): void 'USER_ID' => $userId, 'DURATION' => 10, 'COST' => 250, - 'COST_CURRENCY' => (string)CurrencyList::rub(), + 'COST_CURRENCY' => 'RUB', 'STATUS_CODE' => StatusSipCodeInterface::STATUS_OK, 'FAILED_REASON' => '', 'RECORD_URL' => '', diff --git a/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php b/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php index 112e05ec..79fbbfb8 100644 --- a/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php +++ b/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php @@ -20,7 +20,6 @@ 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\CurrencyList; use Bitrix24\SDK\Services\Telephony\Common\StatusSipCodeInterface; use Bitrix24\SDK\Services\Telephony\Service\ExternalCall; use Bitrix24\SDK\Tests\Integration\Fabric; From b93ca18d210e6c402935db01f311df2e3178194e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Thu, 21 Jul 2022 18:17:14 +0300 Subject: [PATCH 392/647] -edit ExternalCallSearchCrmEntities --- .../ExternalCallSearchCrmEntitiesResult.php | 2 +- .../Telephony/Service/ExternalCall.php | 3 + .../Service/SearchCrmEntitiesTest.php | 88 ++++++++++++++++++- 3 files changed, 89 insertions(+), 4 deletions(-) diff --git a/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesResult.php b/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesResult.php index e5926ffa..6f64b511 100644 --- a/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesResult.php +++ b/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesResult.php @@ -22,7 +22,7 @@ class ExternalCallSearchCrmEntitiesResult extends AbstractResult * @throws \Bitrix24\SDK\Core\Exceptions\BaseException */ - public function getCrmEntities():array + public function getCrmEntitiesSearchResult():array { $res = []; foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { diff --git a/src/Services/Telephony/Service/ExternalCall.php b/src/Services/Telephony/Service/ExternalCall.php index b4f67c6e..96993fb9 100644 --- a/src/Services/Telephony/Service/ExternalCall.php +++ b/src/Services/Telephony/Service/ExternalCall.php @@ -173,6 +173,9 @@ public function attachRecord(string $callId, string $fileName, string $fileConte /** * 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 diff --git a/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php b/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php index 79fbbfb8..504d3403 100644 --- a/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php +++ b/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php @@ -35,6 +35,54 @@ class SearchCrmEntitiesTest extends TestCase 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', time()); + $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 @@ -96,19 +144,19 @@ public function testSearchCrmEntities(): void 'SECOND_NAME' => 'Егорович', 'PHONE' => [ [ - 'VALUE' => $onePhoneTwoContact, + 'VALUE' => $contactPhone, 'VALUE_TYPE' => 'WORK' ] ] ] )->getId(); - $contactId3 = $this->contactService->add( + $contactId2 = $this->contactService->add( [ 'NAME' => 'Хлеб', 'SECOND_NAME' => 'Олегович', 'PHONE' => [ [ - 'VALUE' => $onePhoneTwoContact, + 'VALUE' => $contactPhone, 'VALUE_TYPE' => 'WORK' ] ] @@ -126,6 +174,40 @@ public function testSearchCrmEntities(): void } + /** + * @throws Exception + * @covers ExternalCall::searchCrmEntities + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function testSearchCrmEntitiesWithDifferentPhonePrefix(): void + { + $phoneBody = sprintf('%s', time()); + $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 */ From aa419b1362ebbc76a013f67adbb83e529ccb3fff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Thu, 21 Jul 2022 18:17:54 +0300 Subject: [PATCH 393/647] -edit ExternalCallSearchCrmEntities part 2 --- .../ExternalCallSearchCrmEntitiesResult.php | 4 +- .../Service/SearchCrmEntitiesTest.php | 76 ++++++------------- 2 files changed, 25 insertions(+), 55 deletions(-) diff --git a/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesResult.php b/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesResult.php index 6f64b511..d74d19c7 100644 --- a/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesResult.php +++ b/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesResult.php @@ -18,7 +18,7 @@ class ExternalCallSearchCrmEntitiesResult extends AbstractResult { /** - * @return array + * @return ExternalCallSearchCrmEntitiesItemResult[] * @throws \Bitrix24\SDK\Core\Exceptions\BaseException */ @@ -26,7 +26,7 @@ public function getCrmEntitiesSearchResult():array { $res = []; foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { - $res[] = $item; + $res[] = new ExternalCallSearchCrmEntitiesItemResult($item); } return $res; diff --git a/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php b/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php index 504d3403..56710b72 100644 --- a/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php +++ b/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php @@ -17,14 +17,8 @@ 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; @@ -89,56 +83,39 @@ public function testSearchCrmEntitiesContactFound(): void * @throws Exception * @covers ExternalCall::searchCrmEntities */ - public function testSearchCrmEntities(): void + public function testSearchCrmEntitiesLeadFound(): void { - //Не зарегистрированный телефон - $unusedPhone = '+51045005010'; - $infoAboutNotExistingCustomerResult = $this->externalCallService->searchCrmEntities($unusedPhone)->getCrmEntities(); - self::assertEmpty($infoAboutNotExistingCustomerResult,sprintf('No customers can be found for this number: %s',$unusedPhone)); - - //Зарегистрированный контакт - $phoneNumberClient1 = sprintf('+7%s', time()); - $contactId1 = $this->contactService->add( - [ - 'NAME' => 'Глеб', - 'SECOND_NAME' => 'Егорович', - 'PHONE' => [ - [ - 'VALUE' => $phoneNumberClient1, - 'VALUE_TYPE' => 'WORK' - ] - ] - ] - )->getId(); - $infoAboutClientResult1 = $this->externalCallService->searchCrmEntities($phoneNumberClient1)->getCrmEntities(); - self::assertNotEmpty($infoAboutClientResult1); - $entityType = $infoAboutClientResult1[0]['CRM_ENTITY_TYPE']; - self::assertEquals('CONTACT', $entityType, sprintf('name type incorrect, expected: CONTACT , and your type: %s', $entityType)); - $this->contactService->delete($contactId1)->isSuccess(); - //Зарегистрированный лид - $phoneNumberLead1 = sprintf('+7%s', time()); + $phoneNumberLead = sprintf('+7%s', time()); $leadId1 = $this->leadService->add( [ 'TITLE' => 'ИП Титов', 'NAME' => 'Кирилл', 'PHONE' => [ [ - 'VALUE' => $phoneNumberLead1, + 'VALUE' => $phoneNumberLead, 'VALUE_TYPE' => 'WORK' ] ] ] )->getId(); - $infoAboutLeadResult = $this->externalCallService->searchCrmEntities($phoneNumberLead1)->getCrmEntities(); - self::assertNotEmpty($infoAboutLeadResult); - $entityType = $infoAboutLeadResult[0]['CRM_ENTITY_TYPE']; - self::assertEquals('LEAD', $entityType, sprintf('name type incorrect, expected: LEAD , and your type: %s', $entityType)); - $this->leadService->delete($leadId1); + $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); + } - $onePhoneTwoContact = sprintf('+7%s', time()); - $contactId2 = $this->contactService->add( + /** + * @throws TransportException + * @throws BaseException + * @throws Exception + * @covers ExternalCall::searchCrmEntities + */ + public function testSearchCrmEntitiesMultipleContactsFound(): void + { + $contactPhone = sprintf('+7%s', time()); + $contactId1 = $this->contactService->add( [ 'NAME' => 'Глеб', 'SECOND_NAME' => 'Егорович', @@ -162,16 +139,11 @@ public function testSearchCrmEntities(): void ] ] )->getId(); - $infoAboutTwoContactResult = $this->externalCallService->searchCrmEntities($onePhoneTwoContact)->getCrmEntities(); - var_dump($infoAboutTwoContactResult); - self::assertNotEmpty($infoAboutTwoContactResult); - $entityTypeContact1 = $infoAboutLeadResult[0]['CRM_ENTITY_TYPE']; - $entityTypeContact2 = $infoAboutLeadResult[1]['CRM_ENTITY_TYPE']; - self::assertEquals('CONTACT', $entityTypeContact1, sprintf('name type incorrect, expected: CONTACT , and your type: %s', $entityTypeContact1)); - self::assertEquals('CONTACT', $entityTypeContact2, sprintf('name type incorrect, expected: CONTACT , and your type: %s', $entityTypeContact2)); + $contactIds = [$contactId1,$contactId2]; + $this->externalCallService->searchCrmEntities($contactPhone)->getCrmEntitiesSearchResult(); + $this->assertTrue(in_array($contactId1, $contactIds, true)); + $this->contactService->delete($contactId1); $this->contactService->delete($contactId2); - $this->contactService->delete($contactId3); - } /** @@ -211,12 +183,10 @@ public function testSearchCrmEntitiesWithDifferentPhonePrefix(): void /** * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException */ - public - function setUp(): void + public function setUp(): void { $this->externalCallService = Fabric::getServiceBuilder()->getTelephonyScope()->externalCall(); $this->leadService = Fabric::getServiceBuilder()->getCRMScope()->lead(); - $this->mainService = Fabric::getServiceBuilder()->getMainScope()->main(); $this->contactService = Fabric::getServiceBuilder()->getCRMScope()->contact(); } From 0d6230dcdf7734b43bd6189539886e4c6647a054 Mon Sep 17 00:00:00 2001 From: kirill Date: Fri, 22 Jul 2022 13:55:56 +0300 Subject: [PATCH 394/647] -add test voice --- .../Telephony/Service/ExternalLine.php | 6 +++--- .../Telephony/Service/ExternalCallTest.php | 2 +- .../Service/assets/test-phone-record.mp3 | Bin 0 -> 160954 bytes 3 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 tests/Integration/Services/Telephony/Service/assets/test-phone-record.mp3 diff --git a/src/Services/Telephony/Service/ExternalLine.php b/src/Services/Telephony/Service/ExternalLine.php index 86c5b636..056a6a49 100644 --- a/src/Services/Telephony/Service/ExternalLine.php +++ b/src/Services/Telephony/Service/ExternalLine.php @@ -66,7 +66,7 @@ public function get(): ExternalLinesResult * The method allows you to change the name of the external line * * @param string $lineNumber - * @param string $nameLine + * @param string $newLineName * * @return ExternalLineUpdateResult * @throws \Bitrix24\SDK\Core\Exceptions\BaseException @@ -74,13 +74,13 @@ public function get(): ExternalLinesResult * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalLine_update.php */ - public function update(string $lineNumber, string $nameLine): ExternalLineUpdateResult + public function update(string $lineNumber, string $newLineName): ExternalLineUpdateResult { return new ExternalLineUpdateResult( $this->core->call('telephony.externalLine.update', [ 'NUMBER' => $lineNumber, - 'NAME' => $nameLine, + 'NAME' => $newLineName, ] ) ); diff --git a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php index 8a84b595..efe6436f 100644 --- a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php +++ b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php @@ -293,7 +293,7 @@ public function setUp(): void private function getFileInBase64(): string { - $filePath = __DIR__ . '/TestFile/'; + $filePath = __DIR__ . '/assets/'; $fileName = 'test-phone-record.mp3'; $resBase64 = ''; $handle = fopen($filePath . $fileName, "rb"); diff --git a/tests/Integration/Services/Telephony/Service/assets/test-phone-record.mp3 b/tests/Integration/Services/Telephony/Service/assets/test-phone-record.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..ad8f97381376d1abbfc22bfaecbe5e6dfd188e8f GIT binary patch literal 160954 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�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≷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�^k5wqXC!uozows#-NJjW`KYqTTrgn`XF0rhi)b?$DAjApa9<%6TxrwZ||U z#w=#)rEgtYwjXR(jzY7!fzu)IWZFCvqG=n>JCL19B*)6Wz2m3wcC>D3p)YA`@-K;WQgm{}pr8V!S(hm-LhH?S07&{3+@O?X zkYwzld-*|1Or%U9r*L^Cd`Y_$^zx9s&Pj_=o$%cyV;>S;MagtLc-DF9!nN`KV4f=_pJ$Um_GX`3i&Ap)J zBCeCRI_v76j)EmMM@{0V)6mKz_Myb$2IphINfS@hVXx43SUvq_kbRf9DQc@!%+gudEOX?tB@+ z;~K(U)onVfVpT& zdJdh%9H;Wrlc78L8^B$A8gF{zNU}dK)7pEjx7WH3&_Wr+` zHV>;JXtw*~_D-F|XmWbjSl%HhwJseWT;Shhxu@;P8pTm&NYkg3iJz&qYN^P0m6J zlj7vzNf!6&s-2UkLk1E&lvs1P8Wo3E&wB_alIVKe4~p`Q_aSJN16oe99*fBYx47?} zS?HV(qq%#gPpedqn!xbL-W?L)B5$L?BQ;75=<(S^sJsM{su-WnSO}Lo03RNR+7W+s zbP%=@IlWz;ee4V;l(k~9P*LBH9BDzts`^F|mQ@1%%;VNXsv&p}-y!(_^#h?nj>_xf z>HL}3?qgZW?@w%%m2c+v%~b_VL$vCAddt77LSPff$nv2f$&%*8AB_VVo5f;(+#Kr= z!b^=$q}iQ%4H2d(p_*uWf1T_uqR!)uT1}AE z>A<@vT$aq;?)=n$`namFI!h8wB3pcf*1e$BQ!HCKrN8bje{M!d8StR-}5gEHI>%A!!DoeFxyuE`K~WBs$*r}D2ruO>`487fy? zJQsFN=VH0sqUv z>1TKD@2$<<)9dl;gQ);An!aTjeBZstQQ>r1LdxlZasp zhnL4K;J8T-hKt7t9X6o*ixx~Uf+<;W`fF-_pk!>vYw%)%ZYdVXhAHi8_$qQ-n4P37 zTYD_R46AT()<8`s<`Sx$KK?A=IdqKm1TrB)rO<5H7gXY!VDN4)rC`*wA*T1<~r&$rQh zIqiYr(**^_{Bd?A39D5S9pW?8l&N>@M81&(GKD}5ea1#NS~>M>R-S+Kz>`2qxFU_q zy_p0sw%$Yw7_#lo^ituFi)5 zwK<{gl&El0Ffhe<2;mBO00GbGwXk!jP4P3QCz<{-9hmn)RCTzE+5WNWU8J17^=BU4 zio4h$?u>LdllSWA`f26V*UcMD(w{^*30iL?UhM}Bf*99gURBtY71!aYwcVGqfuFR`a4G2dK>h9Sc_ z&iw!cd=HTMCD4GNqJ!}N6ez)DBA1a z)(f-ezONEfJrwpR2p%lc|7dXkQR67nab0_?RyWnWCO7wI-my_s#L72xATZO*QjrJ% z2$!D5<{X#CAOo?}8{q_+X+#o5C4>ziM4+1%6$UEr#WN^fWi${QSNyxG*MVew8Io7# zNke=MXCE^f#jZbXC?F1pmzknE!VJ3ueygQsY8s?962X4IWIaWvN55dSVmsDiT#}34 zjb+eu8`g7WY^$dJrW<6K08Kg=ssJ2@qCDuPSzfAM}z#Jdx#ns31 z`9;$l{>PG7W4c%uR`&VNyEM~Z(-tJKeM6Oe8w^~&w-WqzDiU!zj83S_%k&bX`MLNE zakre|3O{loicfDx4+<$Ytmlva8-+rp-IBP)At{at!((5fqsi3t-cJ0GzTjaP^8= z3{R?M5yiEz=#YBq$hC>ie_q^ipEWBPJPPQYDNUVec1lJhQcx}=YR`T9bdOqJ+ul8o zpS}9C)L2G4i7`5vTVdaW*HBZ({#$}QXSj`GKPV<=X@mGPO{+$mx)R{uRowv?F{Mdf z?Qspo^Dv6Fm5n3XWoRnS0YD3zkaAdWB!&kuHp`bYgNl`k#}x3UMeFu5 z8qsRu{0hrGP9sRq63vH1l61G1=uOg!$$XZzuVq&X*Y8CqKSM;7UON`f91z7+XZ})* zA&tIA%|{Yt&a2mlhs)`kweMk~o;LJQT7>_FnmE}$)g9g!Wy%j%hQuH8yTh}H?A7gc z<0jrol~9k3q=iXZL02=$APe7hMXR*r_a5(_*J)R&x*#oYnDrHKw9Y^U(J?!z*s&e>ZSB3Mvb-;*7 z8GN&pvT%91$w^cxzx6Nu1vk~Gq5N#1`7J{=m3)qi-Uw?#^0Xs!8_U)2=&lCO>S)H! zZrJA4NaZKt!>_)%)0dKPnBY75wBX|e2O&s)6k$Mg3c-3}enIiv#&jWBd0F?2Tq(hLpKprS*EGz^V& zcem2rT_Pn&N=XRF8NcWI2hQEOICH(9xmbI@zxUm1uXnA=?z9I#N#~*0o2SfawlE9z55O9kHyT7i#@gr#h*tPifpK=c-Gd$=O=1(f#mA` zlk4M*9!dq4YQCadaq?%0%pKHF0)p&ONqn=8o8Zn{=fuP>&9nRbW3VrmMP_jPjN$Jg z%%qT?>r^6We$hZ|ASFY$EIJ8ZptO9Aj*YZ-o^@-s`Uk16+f^>Trc4RWs9_{ZZBxDN zTf+%KmRs-79{HV`mI}*FlXfZ=fhmn$gW8nvgY$a+%M-D0a>hEZF`{ro737x$%0Zbq zgWcN@fqZ=MNnZ`?3ON<2dUt} ze7U*%b%T#qcbqZFP`CGt*jO4d0j_+%Eh6S6#=1f|6~8cd7p5HlspsGJpKLLG0~Ny* zLqT#VHg>Gc!$+A0KsUbu`I@<@k44$)-1@gt>^Y%_{PSbtFG+{! ze6oUUk0e!*nwJ0Maxf$3Qpl3y4ASyykXoWCLaze&eLy#3rm=Y{{qL&i7)2@Uyw6bU z0tASt9gLBZSxpOUJk{<&-4oJD0u-Q;V)EuC5n-wJ-l7Ddc0+qYvx{|jsrY}Pww`8l z219S-1+CCLPP}RtLwTDjIr%nEGH8$S>=-}O1k>_VyxptBpPX0_Yo@cpQ0Ds1UqJ~FIfdWy6WBUrvy5>zL&Eq^r3t8CQ5LWKf7(xh^wyi^e5$cmldUM zq!SdpS{Y7-F!onusEO*huRS}R$jKS?TXeB*+ykJ$@`E{D@i|0WaP`+ukTJUfv%Ivj zWQr(Jv$LET_{;@#{&Z9xNU(noQ|Z=CMCY9bE|)n*?93Rs8~a(0WmX;f1Q~kUXq6p& z@Mq5KcVBrW;PYrp__Bh|`J0~vR}NvSQlIj-b%&*z82Y^Crh}UobK;o`PeXS{1Lk3K zb&86A*c^}kfqexhckx6@CISz)8|{#S)c4H=vBJiJbN9-2X`Pf~;{q@`Uy=*HAB2>= z$D<)tk_IQj?ooBFMStQYPjzaiQRE}TU^y+^$s{%&I(DC_@fj!>2t*)SM19jiLe6Q( zd>A4nG62Xl1jSNU`=Q8WDp>AJfrCNljlOuD{bv^geOmhGGInk{rkDgZ`3fyQcE`V+ zD+$|ua-BU4cv|Z@MlAnS$Jp5VXpicLnkc+-SdI+FVJiEaDlB-i61!ORgQiU|)9-*! z;W~SApeg;vVr)IBn8H*$>v?{FRn|j>NlPaKPfT6NY6eg9kiA_KBY@mD1m>RLf$_O7l?0VG7y?QXl!2Y5N_k=~XE;oA*WP80 zsdV=bL0%C8FRs-f+VotMi2L%pT}5^2Ds-n zU++am{7K$@M|CvsWMgq-@T{=WY3VD5bwdgVfZv}hhw+DAf1xKvPvHCxDqPKmm=iw` z)wcB+da6-35fLK+7D$qVgt^NPm|*?zHiEY}MFw|QxQ4vHo0?T7D}$%_Fs{FmSrq}a zehH=Lp`SJK`=l&YJO(}p?F(3N<$a)2ZPlyPi(KFrzkA+c4o&wna|lG`!YrwZ1HYgA z^L>qKed%W0W#lGHS9tMUXvci*)oqpFWu@!g)I>}B;q9ca`qwW7=G--{#&06I=?=lP z68_){U$?lDI-e1$2J(*?%1A30J_LY;d0It1qp;h?m^PAs#UGE1QflH@rBOIdpvP-q z^9)4R*A3c-bLc1$LDG=HmDbw+d=WFn3|hl5xFyv=R0O+6esNo=g*;WeXs7G|CIJR^ z2UPwU#(ykq4*=xf3SORUG3~Gj*a@|sp+9`iho|W@2}{XPN#pYuZd}hfNPMNDMtUP+ z_z=xZtCT26#z-FN8+dKE0D{K1p4Ik{KpOGRarRu`)d`L0Oma4Ex}(cXvC9@XgL#oe z#Wybe;2G0VDNGa*#urxW8K**RozFB%cifQ?TPIfVo7EKajV)zs!ZGoVhEUC?$x}Z| zO`fkjh{bi0le#-W`Qe_OMPV7$%Ibw7U!HF%%TryGiD83nolX-=bq-&5ag^@c&(y3Y z{Y)wdw4Cmrp4Q*3w^ZA<-~NYL-pP5>XS~t$@K9ftLidkqE`D4cdjHpK$-x`(!Jwv_ zRNfyZTMIW&gD3PT;LwYS43WRiFGh>T2pdL`F?N1klNce(u4?a2Go*4Nw4Uo-t}@@F z-!CWXj}oRP9*oPh{AT4h)pp-7hbd<~%b!>FrdoyWi=NrU&@39penSSuXi`z*AWqZ7 zAr-G(0}{-jW0OIK_wfEspE$5}B=sAx{8>(xn{Me9`^4^*wMDhbyvrU#AuL+}1Zyvv ztkwNDl3l>r>UnwE#^Gq04L_fd+iyRMuh@-4n+jE@yP2S5rejf6S{|ZB^A#FIhWjBS zb}To?&x$gQQ1)VLW!!NxWull4T+fWlh`G&QPE-}-g+=7BuVguE7Su5|B-{LF&7k#T#rcG z{eB@EiH1^M+S05_Pk;;>u`VZyjBK&h%XCzRhu|&L4xG-?Q+cwOS_Xj;oBP3vwVLz!?M%Id4p-q$Q(-rT#f4Diq#*VKf;!`VY7^JQt#$lIuN{7RB zpgy9WWG5C?0e3EYy+qyu&%<<&V7ZI0wejQ0%_@oU4GB(DB;QKct+9LkO+M?a$gpdS zXbqUc#Qg%Q3w?APJ(Nw#DqIFK#8gH&xtqv>uH>1SDs_qq5^#u#yEzsB0!C>ejK{Gi z!=^N?7T&+4`rAGPx|w2AZ#=E`{Oew zl_ml9@jzt2yZ*eooHZB7v9di;c5o!Ds$4re%46!lq7Kucv{cr3#i!G&TWk5P4dj`C zAY-70K^}l8FmNO=S2fD?ovpOPdnOFDrt6RmIgcA-b=7R9!@J?-N`>E=3DBE22yI;@ z(kQ1FLSRRJP^Jn)2w##X+q|pY=5}crBHI0D))A+$Z0}_cnG&cWYW$AV?MRp^@9V_h zDh{53eYSC_tuX`oWYA9yu>rQ7#zT`lqpq^?c+3xcF-QZ*dyRosU{g2LpLqmZ9;P%W#srn0aPSR4pN6x$> z)VT=ve>Z3kK%tGa1Lx)E$Z9x{EX>$lOwkq7Oa4>Uc|ffCPJpznLWS-l(0Kf>5UkUjg)Si!3$^s-r>o~AV~wHd&1ZlIQz)FvRRfSbbGBq;z&k|yG}`@ zPa$9g#ItWln{$W8$Ka|O6;&KuccF^coQ&u?<&h9$_hoDw|IlWW&`9}-LqIT&k#*2P z@ygJgTliOz$JiP>w~VVmLl6sTNK<>01c_lH>e@>Jl1vI z0(3=$43u~H7RR;LcLUT#1%@&3O1b!6yQJL`!HIFOAz-ETls-YZ0pX9UB-V;n^3qrF zQndzxbXp-^AD%~PLdi$tsJXaI&{@yclWqEaKJlK4GMC&WRb_zB(bZeka=O8USX}GP z%(=N|exk%2g{G@5U2&SCF1Wf% z^pS6`{+leG0OZOE@+Z8+hZFq!$Qa{*)RMn`TQN#p0OD2rY}QqiENnap7x&%#@7S#& zy+Z`pTxFcl08;8cJW#opVX{^g>%w?A-98B~J~X+M8ibP&6PLioC?!oOq7~gvW{)Cg zrCVy{FRjLh(SMH`6j_;@22ErXz}B^tRbnf^mJKdu8Ge7ctG%6QL@7)mjJ=}&_BZ}T z<@}$79GAr=GhL_0;_U7AlifT~H%CK#Ltpg;mL4ORjeDG7<2r|f9(hIwYD|NU!5713 zR+>y-z}U&Pc|j%{N3F~H_NyaPR5Gh>3zP&R9AX9|YD3f@Ez@L-CzI%O0|@4djs&3q z%vzU!j$a$olRQC&FLN>aeq{SKB96-mCrYyD>gO7-(xuY2S}dC-qYy)EJ#0r{-CTpO zQ!GAONl9%E6Mf=SIwz)^GbRtJ0js{U4W3fG~r>8&CFr(en;f-p5a;!S|M{f)$ zeiWd?g(rfH3c|ui55XsWRx|>l{`Q7OEKGhGQ+waCVdjH;R^Z>nck-cO|T;>Kp*T&}TF*Uio@S2o4VJB1u(GJb_NY_O^>u3DZAVjTMX zjhneFC;#>L?OGEPDJMZGihMV=2)85_&Nwcfy9y3oB=#JyDZ`2rS8}EA!k3C2K;Ij= z2EK{5A;M7B?=o3BoMlz1A-@|9<_UBB=xrriq=h z<~4!zc%MZ^#iJ0b(Lck$R>K7n08$F=WpPl-EJE-KX7^kxV+!8sBuX#RtsHofqNrMG zoiGjGywnA6z9p?>fbQBlCM1$TGAjP;*_=S3KvF<+{-wnyqzK7=q8}U5it( z3pi2y1N#ncAd@Mm0ruYRZGbiP#~#CqLV*J;g-dRh>7NhYoB3D0AKsqe=}7R>t=ZCa zLV1bY?+4s0eQ+3z!1i#g9H~OzEL19m_JS-y?tyR^J}wYUV1Qyd?r^HpO0}c1_>7?O z+6CLGR`pR+=tO&>R)zB-;-OPF7oC7utIV%o;<*b7VwvfE2|3ONZfSlb6K!-ClTeu# zPW6nyIf;<>6~aclrNR;tmI!F_ zE@q1o2adlo8-f~G$GIx2L~IfB@?xLIjOGTLr3?6CgwpJCC4hLr7HPRB8Lu}>90v&~ z_l%3*X0(Khzk*T}OqQ3YDQ0R?@5iPALG{Pt@&=p?LULn=pW3vGFJ;d^kvB_>inu+^ zm@ldX;G&d$taiKp(rN)I`&=E4`wR$Sw9slx>im6f9S=S|y&rwqy^UpR~^ z%hP)lrl{+)n3rer$wbbN=8J@xi-1Fe)BUMzt;gSMaXH_y$I!Ob*ITQq9NBd0hLv3} zBY6&_(;RZ~Hct?FjO2fBgn17#7P_&U?Mr-N=#>)vR$Fb9E{d<3NRj;u)lfOi5z>%{i z^BqL5tZ*~D`>>F7wpIhDkc7ME{L+NxI7;ad6G!*LKWIvz=RDy-qrzyF%__j*9*emN z=X%)5%;L)jexJ~~iB?{xd85|zig)Z?6IoR+_r8hjgrv*I$q80e*wfKf@f@6b%S6c< zs|4s}De+^?hOJ<+>c?6Ev%Jx%hyX;|{D%N`+PagglxB;qc(gF<+}j8)3oQ`{BiO*m z6BP{uX%koqMgy=}WfkAMhqTwuwT>F}RnO9GEoa$^5MghHK+3AR5O0{3SP~~=tQ;G4 zVj?sN3pn$&sWNYDGP(#-!i1w~`f?n$6J}^N_F^IF{vBs}akYQjk9ptMB~SfbWF8ii zw%w*X4pY~gCl(EQ$pz2Acb0T2~dRw42yYy9$Fv+xetU;ofrgv zgWaYqtA-j84dAYi5Upt0V+6eg(ImwIUED!dqSbHtmsORwIi&9k(#}eM?Qpb+Bh>oh zB`%vJWf7^v3~DX)#k|`)eT@gkk|fX0Bsw4WLc+lx$TU%ny9}txh{9;PS*N7D34mwMxtw>>aH*iRe!@Ev;EX{G%yH&bYKY4+@wzBec8-~IvS$)#= zrPZ>0$p09rsKO>Ihk@yF^&quq7?@_IXSgT^ze(_jxJd=RG;Di_+#hdgYs4~L6#U4w z5qpk5#p(0weZHWx9q9s0|Jo2TvNcujRa@P570$Kj{UGXa7hqLXB&Y@4KreQ#WZ-_t z`&SL80E(U*!D{5r{~G_^KZS!ouW_E@#~}M<4ls7~k<5e(bM#Qovt3Y4;i? zVxmG*;a(w!>&2g9G+Cxv-v2B@A^5b%X-S=Ui^wGNMe;e)=m-X~)u+n4S|xN+34-J_ z`}bDT38Ba~fDfcaMWsmjpaCYMrwRpd%mM+vt7AVOnodvVOuQZtNw;>iaV>|6=PwlJC6-8$+@vf{xFd zTv^f7S|ZVNZNFAg3>WXk_Mi_xnN2LG*TXe_6ocX}s?nJst!xGtu0Frs*9y!cSGizf zS~ekiBx|A%psa~CZ_H@6&CYpVVkwFsg5d?>p^{W=k`}T8iP#o%NoIF)iKX?KZt!I$ zGe1wP-k0Cr_DH_z>OQx2s|+xn&3n}}QGa*-crtc`#@l_aZ#ir4I?L1PHZx?>l#(`p znjELlyTM}|pUnt!#6=Mh7&mllAS@b`X&^H9X$fB_Ox_R;sTaC1AK2m59HG|8*Np#H z4UcdNhXUcM+PUqS29`%;BL;8A?3q@vy1j4Ecsb-J=+^LRGR+K#yBYuKNm21=5r7NZ z$T?(qp2%Y zcPwB(|Fj(B$w!X>DySzapB^;|D&w0_GbL*d+Ju} z!N&E%^6dg>?L5nx@Pn3_dmAef{JwH*=n?E=V@5Ilb1}I&-DmvpIUGR^eoPJ$1vYAJ zX^3%X*D-CoQ$U0;n?r6{VVJ@B0%9=3Yv)AzyS#Nh>zJJ>6}gFfkW-}^F*BIM7(wUI zZZ_SaJfdAavz|_;gFQaJ-GLsAmlYopgO@5J=^l|l(tW9^%j`Lo)^E}dn`y4t`v>-K zxPfG*U=?I8ANe3Qje|SopCfuec1&wLMMN<(J4xu$XBM}tBKXNr89O6i3&q4Rtw=1P zUTOr+pQoq#P4q;0=8X|6YtS6pDt;IaQMj~hF|9@JN~ko(IA#zE0}(_NGKj)qQ_1mo z8=M*9{u3!%&s68@aQ~`WY^VMqwWDFkIAx$?ZC7a!LzYh$|1Q9cJ1I|4wYa%B(1ERd zh^!bZGB?YBFq;t$mzJ1Zt?Iv|sVUQ_vAq^;ilO=IO()tn2=?Yy$F;W$PEXLr{0TbC zBY)K!Qw8#h9;l)>WEK4GGOQCO`Serq9!np9MdtAB9ioud&m$dGIf#^$45YQ$n$HA) z4??N)gTt^GaesMjg>*PMB@|)zkkySkEiMvw|M-hyxp|eQClMty+YWoH%GG(^3k$JL z^z$)#Wi40v8klm9XuhW@zdgSAbZ&V#(?+yqJJ{5|s@so++Quu$2?oR;Z z=LP>7u~l;;OH)6RP~HKhTerL&y>;|6dpdfpZAkU*`*l?bOita`KjoXSPt+q+>^e0_e#8tT($KDZCvun z(cTy{W7{KLUo8`?OD5rDQDy7P_^&~!89(Lv-YNF6`Ud2SAp)>+(%|;+xz&>RV1fv} z-xCi_4I33{eANx#2U?IY0T|N*;UV2WTpXuKU@BA%I0+?ALZ2P9O8yWX4riQ6fF%k& zrYKWw^j$>=F&9ZZ8I{lswsF9UI&{Ww5Nk1{dRu&CHu*X;)a1bfL+P0)|IYbC07Y3Q zZ&mF=ey0HJcVkB59o};q=*#?&;G=l>R7es1bX*aatKFk>bBT4wc;?%`8`nOpH<#!6 z`%GOA`N=bHZ~;Pkt6!H-)cTgk=W_SLW&6XZH4sIp zo0bAtKxy`{XFw%DE^u0>N@wXsp2+y)ntM*9NnlA3D|1CO_Je%osIyry!u7SzJPz}R zJ`K|I1?zKFEKzHi36GULalOBsyk$SmS%pc0 z$^%6xP*pdH<@YiFib`5?^Wcn`_3>cyuHizH%gV7HWzGE|yRBus2P|QGeSWmBZGLRA z)PC>t{nsa}1pxG@`eS1|n{0td1jMn{BKH8^3++iFMp0vVrg4QsfZ_@kiN@Xd8mV+& zD}P)WPcuRny#doME0G#gEOGfB-IBX4SIzRD5z-*Y|yIrV@S z%1;_uyc;w1bTYoj7TGDQOGzOPV#wcGA7o_lIZlwp>0%KM(7avGpPvUhzRv#FZE=st zJr>7l5xmfc!67|Sbn+hQJtZz3JRAfdNZJ|;p3n$K55*gZWOo|AYFCqAb1^irY8(ZV z5f3h?=cI8TcMf+GrUM<=favjG#8{1l2^*7y) zvxHh@Jvg;dE&` za?n)a5}4~6zK>A0dAafF`Ss5uYWJ5*Pi{g@fU-=VfUcBgv8>TNQATu&7>@H^P$1e! zbZxShQ89!}qLo@U-K7BhSnEbsdv9A!cue|L94A5wZJGTY2GiK(g*~YRqF;jo@BN=IhMzb9DOZu2o<1zl z)*F~W_{8)jIxV`zP$>q94r(8%GcAfCP|Mxxw}tm&p`ZsT`zP`G*4JrS6)qd*!k`ZO zH2Z8_OTg94wd)d>aXy(%85&#vso<%0s=;I}t$*Yj(Jb1}!UjQb! z4t@}1DeO2IH>KUWmlI%fIs2;<<5eF$N1ONH-b)&GotMTgxS5!1rN_aJrgW;Jtq(=jK?&2g*qBNecI${KZ>XO#9z%mu^*eMBrIVpu)W z&{z@f=U7d>(!YT5hFnRbQ6|>Ut;VHBhj%9i`IDwd~h8z5Sf{Q^e-{agcT?)8|N z0s{nr#s=pvo}RACdz*0XJe49r0CMyK2sUI_O%@auOu)pTClk!0@{V~LRMle#=Ja-_ zw_{OejhO%cDz2qbIABvmFFkbnG1$EdN!*4V)Yq+*}3rwI)P1;$ni% zDwe|eU}7A!JVOdFISMhbo&iFt2#-KoIu_s%s>!I!^K Date: Fri, 22 Jul 2022 14:16:47 +0300 Subject: [PATCH 395/647] -add rus docks in CHANGELOG.md --- CHANGELOG.md | 4 ++-- README.md | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bdec92c6..53fd6958 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ## 2.0-alpha.7 — 13.06.2022 ### Added - +* add new scope `Telephony` and services [add Telephony support](https://github.com/mesilov/bitrix24-php-sdk/issues/291) * add new scope `UserConsent` and services [add UserConsent support](https://github.com/mesilov/bitrix24-php-sdk/issues/285) * add new scope `Placements` and services [add Placements support](https://github.com/mesilov/bitrix24-php-sdk/issues/274) * add new service `Leads` in scope «CRM» [add Leads support](https://github.com/mesilov/bitrix24-php-sdk/issues/282) @@ -25,7 +25,7 @@ * add method `Services\Main\Service::checkUserAccess` Checks if the current user has at least one permission of those specified by the ACCESS parameter. * add method `Services\Main\Service::getMethodAffordability` Method returns 2 parameters - isExisting and isAvailable - +* add money type support by [phpmoney](https://github.com/moneyphp/money) ### Changed * update scope list [расширить и актуализировать доступные скоупы](https://github.com/mesilov/bitrix24-php-sdk/issues/280) diff --git a/README.md b/README.md index 0feecf02..643aae7f 100644 --- a/README.md +++ b/README.md @@ -332,4 +332,53 @@ Symfony HttpClient JSON по HTTP/2 или HTTP/1.1 -## Спонсоры \ No newline at end of file +## Спонсоры + +### Тесты + +Тесты расположены в папке `tests` и бывают двух типов: юнит и интеграционные. +В папке `tests` создайте файл `.env.local` и заполните переменные из файла `.env`. + +#### Юнит тесты + +**Быстрые**, выполняются без сетевого взаимодействия с Битрикс 24. + +```shell +composer phpunit-run-unit-test +``` + +#### Интеграционные тесты + +**Медленные** тесты покрывают полный жизненный цикл CRUD операций подключение к Битрикс 24 происходи с помощью веб-хука. + +❗ Не запускайте интеграционные тесты на ваших production порталах они удалят все ваши данные ❗️ + +Для запуска интеграционных тестов вам нужно: + +1. Создать [Новый портал Битрикс 24](https://www.bitrix24.ru/create.php?p=255670) для запуска тестов. +2. Перейти в левое меню и нажать "Карта сайта". +3. Найти меню для "Разработчиков" +4. Кликнуть в меню «Другое» +5. Кликнуть в меню «Входящий веб-хук» +6. Выбрать все нужные расширения и нажать кнопку "сохранить". +7. Создать файл `/tests/.env.local` с переменными окружения которые скопировать из файла `/tests/.env` . + +```yaml +APP_ENV=dev +BITRIX24_WEBHOOK=https:// your portal webhook url +INTEGRATION_TEST_LOG_LEVEL=500 +``` + +8. Запуск из командной строки. + +```shell +composer composer phpunit-run-integration-tests +``` + +#### Статический анализ кодовой базы – phpstan + +Запуск из командной строки. + +```shell + composer phpstan-analyse +``` From 679cd87a2e5f41decebdf391d9c1c63bfd14e52b Mon Sep 17 00:00:00 2001 From: kirill Date: Fri, 22 Jul 2022 15:20:12 +0300 Subject: [PATCH 396/647] -edit array types --- src/Services/Telephony/Service/Call.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Services/Telephony/Service/Call.php b/src/Services/Telephony/Service/Call.php index dc64210c..f24be08f 100644 --- a/src/Services/Telephony/Service/Call.php +++ b/src/Services/Telephony/Service/Call.php @@ -25,7 +25,7 @@ class Call extends AbstractService * * @param string $callId * @param Money $callCosts - * @param array>> $messages + * @param array> $messages * @return \Bitrix24\SDK\Services\Telephony\Result\CallAttachTranscriptionResult * @throws \Bitrix24\SDK\Core\Exceptions\BaseException * @throws \Bitrix24\SDK\Core\Exceptions\TransportException From c870984fd333119097bab73fdec368c034850b26 Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 22 Jul 2022 15:31:24 +0300 Subject: [PATCH 397/647] fix CONTRIBUTING.md Signed-off-by: mesilov --- CONTRIBUTING.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 47e4633c..14eb68a4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,7 +6,9 @@ 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 test` + `composer phpstan-analyse` + `composer phpunit-run-unit-tests` + `composer phpunit-run-integration-tests` ## Adding new features @@ -19,8 +21,8 @@ New features that does not have any BC Breaks are going to be added in next mino In order to fix codding standards please exeecute: -``` -composer cs:php:fix +```shell +composer phpstan-analyse ``` ## Patches and bugfixes @@ -28,12 +30,10 @@ composer cs:php:fix 1. Check the oldest version that patch/bug fix can be applied. 2. Create PR against that version -For example if you are fixing pattern expander that was introduced in version 1.1 make sure that PR with fix -is created against version 1.1, not master or 2.0 ## The actual contribution 1. Make the changes/additions to the code, committing often and making clear what you've done -2. Make sure you write tests for your code, located in the folder structure `tests/Coduo/PHPMatcher/...` -3. Run your tests (often and while coding): `./bin/phpunit` +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 From 17329d87d95617c57fdb09745ca49e54afd92eca Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 22 Jul 2022 15:41:06 +0300 Subject: [PATCH 398/647] fix CHANGELOG.md Signed-off-by: mesilov --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d5b28b2..6d026835 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ ACCESS parameter. * add method `Services\Main\Service::getMethodAffordability` Method returns 2 parameters - isExisting and isAvailable * add money type support by [phpmoney](https://github.com/moneyphp/money) + ### Changed * update scope list [расширить и актуализировать доступные скоупы](https://github.com/mesilov/bitrix24-php-sdk/issues/280) From eb1480645324ecf4865e857eab1e6584c7b0df78 Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 22 Jul 2022 16:36:22 +0300 Subject: [PATCH 399/647] fix integration tests Signed-off-by: mesilov --- .../Service/SearchCrmEntitiesTest.php | 88 ++++++++++--------- 1 file changed, 48 insertions(+), 40 deletions(-) diff --git a/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php b/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php index 56710b72..91365b68 100644 --- a/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php +++ b/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php @@ -52,25 +52,30 @@ public function testSearchCrmEntitiesWithEmptyResult(): void public function testSearchCrmEntitiesContactFound(): void { //Зарегистрированный контакт - $phoneNumberClient = sprintf('+7%s', time()); + $phoneNumberClient = sprintf('+7%s%s', time(), random_int(1, PHP_INT_MAX)); $contactId = $this->contactService->add( [ - 'NAME' => 'Глеб', + 'NAME' => 'Глеб', 'SECOND_NAME' => 'Егорович', - 'PHONE' => [ + 'PHONE' => [ [ - 'VALUE' => $phoneNumberClient, - 'VALUE_TYPE' => 'WORK' - ] - ] + '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)); + 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); @@ -86,23 +91,27 @@ public function testSearchCrmEntitiesContactFound(): void public function testSearchCrmEntitiesLeadFound(): void { //Зарегистрированный лид - $phoneNumberLead = sprintf('+7%s', time()); + $phoneNumberLead = sprintf('+7%s%s', time(), random_int(1, PHP_INT_MAX)); $leadId1 = $this->leadService->add( [ 'TITLE' => 'ИП Титов', - 'NAME' => 'Кирилл', + 'NAME' => 'Кирилл', 'PHONE' => [ [ - 'VALUE' => $phoneNumberLead, - 'VALUE_TYPE' => 'WORK' - ] - ] + 'VALUE' => $phoneNumberLead, + 'VALUE_TYPE' => 'WORK', + ], + ], ] )->getId(); $infoAboutLeadResult = $this->externalCallService->searchCrmEntities($phoneNumberLead)->getCrmEntitiesSearchResult(); - $this->assertCount(1,$infoAboutLeadResult); + $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)); + 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); } @@ -114,32 +123,32 @@ public function testSearchCrmEntitiesLeadFound(): void */ public function testSearchCrmEntitiesMultipleContactsFound(): void { - $contactPhone = sprintf('+7%s', time()); + $contactPhone = sprintf('+7%s%s', time(), random_int(1, PHP_INT_MAX)); $contactId1 = $this->contactService->add( [ - 'NAME' => 'Глеб', + 'NAME' => 'Глеб', 'SECOND_NAME' => 'Егорович', - 'PHONE' => [ + 'PHONE' => [ [ - 'VALUE' => $contactPhone, - 'VALUE_TYPE' => 'WORK' - ] - ] + 'VALUE' => $contactPhone, + 'VALUE_TYPE' => 'WORK', + ], + ], ] )->getId(); $contactId2 = $this->contactService->add( [ - 'NAME' => 'Хлеб', + 'NAME' => 'Хлеб', 'SECOND_NAME' => 'Олегович', - 'PHONE' => [ + 'PHONE' => [ [ - 'VALUE' => $contactPhone, - 'VALUE_TYPE' => 'WORK' - ] - ] + 'VALUE' => $contactPhone, + 'VALUE_TYPE' => 'WORK', + ], + ], ] )->getId(); - $contactIds = [$contactId1,$contactId2]; + $contactIds = [$contactId1, $contactId2]; $this->externalCallService->searchCrmEntities($contactPhone)->getCrmEntitiesSearchResult(); $this->assertTrue(in_array($contactId1, $contactIds, true)); $this->contactService->delete($contactId1); @@ -154,19 +163,19 @@ public function testSearchCrmEntitiesMultipleContactsFound(): void */ public function testSearchCrmEntitiesWithDifferentPhonePrefix(): void { - $phoneBody = sprintf('%s', time()); + $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' => 'Глеб', + 'NAME' => 'Глеб', 'SECOND_NAME' => 'Егорович', - 'PHONE' => [ + 'PHONE' => [ [ - 'VALUE' => $contactPhone1, - 'VALUE_TYPE' => 'WORK' - ] - ] + 'VALUE' => $contactPhone1, + 'VALUE_TYPE' => 'WORK', + ], + ], ] )->getId(); @@ -177,7 +186,6 @@ public function testSearchCrmEntitiesWithDifferentPhonePrefix(): void $this->assertEmpty($infoAboutTwoContactsResult2); $this->assertEmpty($infoAboutTwoContactsResult3); $this->contactService->delete($contactId1); - } /** From 0e685c3b6156d68ce653bd59b19c06e82aa997fb Mon Sep 17 00:00:00 2001 From: kirill Date: Fri, 22 Jul 2022 17:48:46 +0300 Subject: [PATCH 400/647] -test serializer --- composer.json | 8 +++-- .../Telephony/testSerializer/person.php | 35 +++++++++++++++++++ .../Telephony/testSerializer/serializer.php | 21 +++++++++++ 3 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 src/Services/Telephony/testSerializer/person.php create mode 100644 src/Services/Telephony/testSerializer/serializer.php diff --git a/composer.json b/composer.json index 0a09205e..799df0ef 100644 --- a/composer.json +++ b/composer.json @@ -19,6 +19,7 @@ "require": { "php": "7.4.*|8.*", "ext-json": "*", + "ext-bcmath": "*", "ext-curl": "*", "psr/log": "^1.1.4 || ^2.0 || ^3.0", "fig/http-message-util": "1.1.*", @@ -26,7 +27,9 @@ "symfony/http-client-contracts": "^2.5 || ^3.1", "symfony/http-foundation": "5.4.* || 6.*", "symfony/event-dispatcher": "5.4.* || 6.*", - "ramsey/uuid": "^4.2.3" + "ramsey/uuid": "^4.2.3", + "moneyphp/money": "3.* || 4.*", + "symfony/serializer": "^6.1" }, "require-dev": { "monolog/monolog": "2.1.*", @@ -36,7 +39,8 @@ "phpstan/phpstan": "1.*", "phpunit/phpunit": "9.5.*", "symfony/stopwatch": "5.4.* || 6.*", - "roave/security-advisories": "dev-master" + "roave/security-advisories": "dev-master", + "ext-intl": "*" }, "autoload": { "psr-4": { diff --git a/src/Services/Telephony/testSerializer/person.php b/src/Services/Telephony/testSerializer/person.php new file mode 100644 index 00000000..4e72acfe --- /dev/null +++ b/src/Services/Telephony/testSerializer/person.php @@ -0,0 +1,35 @@ +name; + } + + public function getLastName() + { + return $this->lastName; + } + + + // Setters + public function setName($name) + { + $this->name = $name; + } + + public function setLastName($lastName) + { + $this->lastName = $lastName; + } + +} \ No newline at end of file diff --git a/src/Services/Telephony/testSerializer/serializer.php b/src/Services/Telephony/testSerializer/serializer.php new file mode 100644 index 00000000..96808e9e --- /dev/null +++ b/src/Services/Telephony/testSerializer/serializer.php @@ -0,0 +1,21 @@ +setName('Kirill'); +$person->setLastName('Hramov'); + +$jsonContent = $serializer->serialize($person, 'json'); + +// $jsonContent contains {"name":"foo","age":99,"sportsperson":false,"createdAt":null} + +echo $jsonContent; // or return it in a Response \ No newline at end of file From 4e27c5ba28fbffcba3d3cf16e22f0a8bcfbdc3b8 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 23 Jul 2022 14:07:56 +0300 Subject: [PATCH 401/647] add operation timings Signed-off-by: mesilov --- CHANGELOG.md | 4 +- src/Core/Response/DTO/Time.php | 60 ++++++++++++++++++----- tests/Unit/Core/Response/DTO/TimeTest.php | 49 +++++++++++++----- 3 files changed, 89 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d026835..c44ccf7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 2.0-alpha.7 — 23.07.2022 ### Added + * add new scope `Telephony` and services [add Telephony support](https://github.com/mesilov/bitrix24-php-sdk/issues/291) * add new scope `UserConsent` and services [add UserConsent support](https://github.com/mesilov/bitrix24-php-sdk/issues/285) * add new scope `Placements` and services [add Placements support](https://github.com/mesilov/bitrix24-php-sdk/issues/274) @@ -32,6 +33,7 @@ ACCESS parameter. * add method `Services\Main\Service::getMethodAffordability` Method returns 2 parameters - isExisting and isAvailable * add money type support by [phpmoney](https://github.com/moneyphp/money) +* add support fields `operating` and `operating_reset_at` at `Bitrix24\SDK\Core\Response\DTO\Time` datastructures ### Changed @@ -45,7 +47,7 @@ * add bugfix for batch method for reverse order queries * fix type compatible errors for `Core\Result\AbstractItem` -* fix error in `NetworkTimingParser`, [error in NetworkTimingsErrorInfo](https://github.com/mesilov/bitrix24-php-sdk/issues/277) +* fix error in `NetworkTimingParser`, [error in NetworkTimingsErrorInfo](https://github.com/mesilov/bitrix24-php-sdk/issues/277) * fix error in `RenewedAccessToken` DTO, remove `Scope` enum [UnknownScopeCodeException - in refresh token response](https://github.com/mesilov/bitrix24-php-sdk/issues/295) diff --git a/src/Core/Response/DTO/Time.php b/src/Core/Response/DTO/Time.php index 3d41ec45..e1302aa1 100644 --- a/src/Core/Response/DTO/Time.php +++ b/src/Core/Response/DTO/Time.php @@ -4,6 +4,8 @@ namespace Bitrix24\SDK\Core\Response\DTO; +use DateTimeImmutable; + /** * Class Time * @@ -11,12 +13,22 @@ */ class Time { - protected float $start; - protected float $finish; - protected float $duration; - protected float $processing; - protected \DateTimeImmutable $dateStart; - protected \DateTimeImmutable $dateFinish; + private float $start; + private float $finish; + private float $duration; + private float $processing; + /** + * @var float $operating sum of query execution time + * @see https://training.bitrix24.com/rest_help/rest_sum/operating.php + */ + private float $operating; // time in seconds + private DateTimeImmutable $dateStart; + private DateTimeImmutable $dateFinish; + /** + * @var int|null time to reset nearest limit part + * @see https://training.bitrix24.com/rest_help/rest_sum/operating.php + */ + private ?int $operatingResetAt; /** * Time constructor. @@ -25,23 +37,29 @@ class Time * @param float $finish * @param float $duration * @param float $processing + * @param float $operating * @param \DateTimeImmutable $dateStart * @param \DateTimeImmutable $dateFinish + * @param int|null $operatingResetAt */ public function __construct( float $start, float $finish, float $duration, float $processing, - \DateTimeImmutable $dateStart, - \DateTimeImmutable $dateFinish + float $operating, + DateTimeImmutable $dateStart, + DateTimeImmutable $dateFinish, + ?int $operatingResetAt ) { $this->start = $start; $this->finish = $finish; $this->duration = $duration; $this->processing = $processing; + $this->operating = $operating; $this->dateStart = $dateStart; $this->dateFinish = $dateFinish; + $this->operatingResetAt = $operatingResetAt; } /** @@ -76,10 +94,26 @@ public function getProcessing(): float return $this->processing; } + /** + * @return float + */ + public function getOperating(): float + { + return $this->operating; + } + + /** + * @return int|null + */ + public function getOperatingResetAt(): ?int + { + return $this->operatingResetAt; + } + /** * @return \DateTimeImmutable */ - public function getDateStart(): \DateTimeImmutable + public function getDateStart(): DateTimeImmutable { return $this->dateStart; } @@ -87,7 +121,7 @@ public function getDateStart(): \DateTimeImmutable /** * @return \DateTimeImmutable */ - public function getDateFinish(): \DateTimeImmutable + public function getDateFinish(): DateTimeImmutable { return $this->dateFinish; } @@ -105,8 +139,10 @@ public static function initFromResponse(array $response): self (float)$response['finish'], (float)$response['duration'], (float)$response['processing'], - new \DateTimeImmutable($response['date_start']), - new \DateTimeImmutable($response['date_finish']) + (float)$response['operating'], + new DateTimeImmutable($response['date_start']), + new DateTimeImmutable($response['date_finish']), + $response['operating_reset_at'] ?? null ); } } \ No newline at end of file diff --git a/tests/Unit/Core/Response/DTO/TimeTest.php b/tests/Unit/Core/Response/DTO/TimeTest.php index 46ef120b..64f597b2 100644 --- a/tests/Unit/Core/Response/DTO/TimeTest.php +++ b/tests/Unit/Core/Response/DTO/TimeTest.php @@ -5,6 +5,7 @@ namespace Bitrix24\SDK\Tests\Unit\Core\Response\DTO; use Bitrix24\SDK\Core\Response\DTO\Time; +use Generator; use PHPUnit\Framework\TestCase; /** @@ -15,26 +16,52 @@ class TimeTest extends TestCase { /** - * @throws \Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException + * @throws \Exception + * @dataProvider timingsDataProvider */ - public function testInitFromResponseData(): void + public function testInitFromResponseData(array $result): void { - $result = [ - 'start' => 1604098405.469694, - 'finish' => 1604098405.50439, - 'duration' => 0.034696102142333984, - 'processing' => 6.198883056640625E-5, - 'date_start' => '2020-10-31T01:53:25+03:00', - 'date_finish' => '2020-10-31T01:53:26+03:00', - ]; - $time = Time::initFromResponse($result); $this->assertEquals($result['start'], $time->getStart()); $this->assertEquals($result['finish'], $time->getFinish()); $this->assertEquals($result['duration'], $time->getDuration()); $this->assertEquals($result['processing'], $time->getProcessing()); + $this->assertEquals($result['operating'], $time->getOperating()); + $this->assertEquals($result['operating_reset_at'], $time->getOperatingResetAt()); $this->assertEquals($result['date_start'], $time->getDateStart()->format(\DATE_ATOM)); $this->assertEquals($result['date_finish'], $time->getDateFinish()->format(\DATE_ATOM)); } + + /** + * @return \Generator + */ + public function timingsDataProvider(): Generator + { + yield 'without operating reset at' => [ + [ + 'start' => 1604098405.469694, + 'finish' => 1604098405.50439, + 'duration' => 0.034696102142333984, + 'processing' => 6.198883056640625E-5, + 'operating' => 0.11336898803710938, + 'operating_reset_at' => null, + 'date_start' => '2020-10-31T01:53:25+03:00', + 'date_finish' => '2020-10-31T01:53:26+03:00', + ], + ]; + + yield 'with operating reset at' => [ + [ + 'start' => 1604098405.469694, + 'finish' => 1604098405.50439, + 'duration' => 0.034696102142333984, + 'processing' => 6.198883056640625E-5, + 'operating' => 0.11336898803710938, + 'operating_reset_at' => 20, + 'date_start' => '2020-10-31T01:53:25+03:00', + 'date_finish' => '2020-10-31T01:53:26+03:00', + ], + ]; + } } From 76d68d76bf452a06b3e629b240e3b23c30581c3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Mon, 25 Jul 2022 15:05:18 +0300 Subject: [PATCH 402/647] -add test serialize and deserialize --- composer.json | 4 +- .../Telephony/testSerializer/serializer.php | 21 ------- .../Unit/Services/TestPerson/Person.php | 4 +- tests/Unit/Services/TestPerson/PersonTest.php | 58 +++++++++++++++++++ 4 files changed, 63 insertions(+), 24 deletions(-) delete mode 100644 src/Services/Telephony/testSerializer/serializer.php rename src/Services/Telephony/testSerializer/person.php => tests/Unit/Services/TestPerson/Person.php (86%) create mode 100644 tests/Unit/Services/TestPerson/PersonTest.php diff --git a/composer.json b/composer.json index 799df0ef..fdbf9b3b 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,9 @@ "symfony/event-dispatcher": "5.4.* || 6.*", "ramsey/uuid": "^4.2.3", "moneyphp/money": "3.* || 4.*", - "symfony/serializer": "^6.1" + "symfony/serializer": "6.*||^6.1", + "symfony/routing": "^4.4|^5.3|^6.0", + "symfony/property-access": "6.* || 6.1.*" }, "require-dev": { "monolog/monolog": "2.1.*", diff --git a/src/Services/Telephony/testSerializer/serializer.php b/src/Services/Telephony/testSerializer/serializer.php deleted file mode 100644 index 96808e9e..00000000 --- a/src/Services/Telephony/testSerializer/serializer.php +++ /dev/null @@ -1,21 +0,0 @@ -setName('Kirill'); -$person->setLastName('Hramov'); - -$jsonContent = $serializer->serialize($person, 'json'); - -// $jsonContent contains {"name":"foo","age":99,"sportsperson":false,"createdAt":null} - -echo $jsonContent; // or return it in a Response \ No newline at end of file diff --git a/src/Services/Telephony/testSerializer/person.php b/tests/Unit/Services/TestPerson/Person.php similarity index 86% rename from src/Services/Telephony/testSerializer/person.php rename to tests/Unit/Services/TestPerson/Person.php index 4e72acfe..41c3c19f 100644 --- a/src/Services/Telephony/testSerializer/person.php +++ b/tests/Unit/Services/TestPerson/Person.php @@ -2,9 +2,9 @@ declare(strict_types=1); -namespace Bitrix24\SDK\Services\Telephony\testSerializer; +namespace Bitrix24\SDK\Tests\Unit\Services\TestPerson; -class person +class Person { private string $name; private string $lastName; diff --git a/tests/Unit/Services/TestPerson/PersonTest.php b/tests/Unit/Services/TestPerson/PersonTest.php new file mode 100644 index 00000000..0027610a --- /dev/null +++ b/tests/Unit/Services/TestPerson/PersonTest.php @@ -0,0 +1,58 @@ +setName('Kirill'); + $person->setLastName('Khramov'); + + + $jsonContent = $serializer->serialize($person, 'json'); + + + self::assertNotEmpty($jsonContent); + echo $jsonContent; // or return it in a Response + } + + /** + * @test + */ + public function DeserializeTest():void{ + $encoders = [new XmlEncoder(), new JsonEncoder()]; + $normalizers = [new ObjectNormalizer()]; + + $serializer = new Serializer($normalizers, $encoders); + + $data = << + Kirill + Khramov + false + + EOF; + + $person = $serializer->deserialize($data, Person::class, 'xml'); + var_dump($person); + self::assertNotEmpty($person); + } +} \ No newline at end of file From ef264a96de201b7b44395e90d793cac33de00dbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Tue, 26 Jul 2022 18:02:44 +0300 Subject: [PATCH 403/647] -add test normalize -and edit NetworkTimingsParser.php --- .../TransportLayer/NetworkTimingsParser.php | 14 ++++---- tests/Unit/Services/TestPerson/PersonTest.php | 33 +++++++++++++++++++ 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/src/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser.php b/src/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser.php index 696a08a9..9d2b2711 100644 --- a/src/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser.php +++ b/src/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser.php @@ -28,12 +28,12 @@ public function __construct(array $httpClientResponseInfo) // get the name lookup time // Time from the start until the name resolving was completed. // When a redirect is followed, the time from each request is added together. - 'namelookup_time_us' => $httpClientResponseInfo['namelookup_time_us'], + 'namelookup_time' => $httpClientResponseInfo['namelookup_time'], // total time in seconds from the start until the connection to the remote host (or proxy) was completed in MICROSECONDS // https://curl.se/libcurl/c/CURLINFO_CONNECT_TIME.html // When a redirect is followed, the time from each request is added together. - 'connect_time_us' => $httpClientResponseInfo['connect_time_us'], + 'connect_time' => $httpClientResponseInfo['connect_time'], // time until the SSL/SSH handshake is completed in MICROSECONDS // https://curl.se/libcurl/c/CURLINFO_APPCONNECT_TIME.html @@ -41,7 +41,7 @@ public function __construct(array $httpClientResponseInfo) // This time is most often close to the CURLINFO_PRETRANSFER_TIME time, except for cases such as HTTP pipelining // where the pretransfer time can be delayed due to waits in line for the pipeline and more. // When a redirect is followed, the time from each request is added together. - 'appconnect_time_us' => $httpClientResponseInfo['appconnect_time_us'], + 'appconnect_time' => $httpClientResponseInfo['appconnect_time'] ?? null, // time until the file transfer start in MICROSECONDS // https://curl.se/libcurl/c/CURLINFO_PRETRANSFER_TIME.html @@ -49,28 +49,28 @@ public function __construct(array $httpClientResponseInfo) // This time-stamp includes all pre-transfer commands and negotiations that are specific to the particular // protocol(s) involved. It includes the sending of the protocol- specific protocol instructions that triggers a transfer. // When a redirect is followed, the time from each request is added together. - 'pretransfer_time_us' => $httpClientResponseInfo['pretransfer_time_us'], + 'pretransfer_time' => $httpClientResponseInfo['pretransfer_time'], // time for all redirection steps in MICROSECONDS // https://curl.se/libcurl/c/CURLINFO_REDIRECT_TIME.html // it took for all redirection steps include name lookup, connect, pretransfer and transfer before // final transaction was started. // CURLINFO_REDIRECT_TIME contains the complete execution time for multiple redirections. - 'redirect_time_us' => $httpClientResponseInfo['redirect_time_us'], + 'redirect_time' => $httpClientResponseInfo['redirect_time'], // time until the first byte is received in MICROSECONDS // it took from the start until the first byte is received by libcurl // https://curl.se/libcurl/c/CURLINFO_STARTTRANSFER_TIME.html // This includes CURLINFO_PRETRANSFER_TIME and also the time the server needs to calculate the result. // When a redirect is followed, the time from each request is added together. - 'starttransfer_time_us' => $httpClientResponseInfo['starttransfer_time_us'], + 'starttransfer_time' => $httpClientResponseInfo['starttransfer_time'], // total time of previous transfer in MICROSECONDS // https://curl.se/libcurl/c/CURLINFO_TOTAL_TIME.html // total time in seconds for the previous transfer, including name resolving, TCP connect etc. // The double represents the time in seconds, including fractions. // When a redirect is followed, the time from each request is added together. - 'total_time_us' => $httpClientResponseInfo['total_time_us'], + 'total_time' => $httpClientResponseInfo['total_time'], ]; } diff --git a/tests/Unit/Services/TestPerson/PersonTest.php b/tests/Unit/Services/TestPerson/PersonTest.php index 0027610a..015ebe75 100644 --- a/tests/Unit/Services/TestPerson/PersonTest.php +++ b/tests/Unit/Services/TestPerson/PersonTest.php @@ -3,11 +3,17 @@ namespace Bitrix24\SDK\Tests\Unit\Services\TestPerson; +use Money\Currency; use PHPUnit\Framework\TestCase; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Encoder\XmlEncoder; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Serializer; +use Money\Money; +use Money\Currencies\ISOCurrencies; +use Money\Formatter\AggregateMoneyFormatter; +use Money\Formatter\IntlMoneyFormatter; +use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; class PersonTest extends TestCase @@ -27,6 +33,7 @@ public function SerializerTest():void{ $person->setLastName('Khramov'); + $jsonContent = $serializer->serialize($person, 'json'); @@ -55,4 +62,30 @@ public function DeserializeTest():void{ var_dump($person); self::assertNotEmpty($person); } + + /** + * @test + * @throws \Symfony\Component\Serializer\Exception\ExceptionInterface + */ + public function NormalizeMoneyTest():void + { + $encoders = [new XmlEncoder(), new JsonEncoder()]; + $normalizers = [new ObjectNormalizer()]; + + $serializer = new Serializer($normalizers, $encoders); + + $dollars = new Money(100,new Currency('USD')); + + $numberFormatter = new \NumberFormatter('en_US', \NumberFormatter::CURRENCY); + $intlFormatter = new IntlMoneyFormatter($numberFormatter, new ISOCurrencies()); + + $moneyFormatter = new AggregateMoneyFormatter([ + 'USD' => $intlFormatter, + ]); + + $money = $moneyFormatter->format($dollars); + $jsonContent = $serializer->normalize($money,null, [AbstractNormalizer::ATTRIBUTES => ['amount']]); + var_dump($jsonContent); + self::assertNotEmpty($money); + } } \ No newline at end of file From 4f27a7e79592563e2dbe7453a1088a2622325b59 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 28 Jul 2022 15:00:19 +0300 Subject: [PATCH 404/647] add telephony events Signed-off-by: mesilov --- src/Services/Telephony/Common/CallType.php | 50 +++++- .../Telephony/Common/CrmEntityType.php | 33 ++++ .../Common/StatusSipCodeInterface.php | 155 +++++++++--------- .../Events/OnExternalCallBackStart.php | 60 +++++++ .../Requests/Events/OnExternalCallStart.php | 95 +++++++++++ .../Requests/Events/OnVoximplantCallEnd.php | 114 +++++++++++++ .../Requests/Events/OnVoximplantCallInit.php | 54 ++++++ .../Requests/Events/OnVoximplantCallStart.php | 29 ++++ 8 files changed, 504 insertions(+), 86 deletions(-) create mode 100644 src/Services/Telephony/Requests/Events/OnExternalCallBackStart.php create mode 100644 src/Services/Telephony/Requests/Events/OnExternalCallStart.php create mode 100644 src/Services/Telephony/Requests/Events/OnVoximplantCallEnd.php create mode 100644 src/Services/Telephony/Requests/Events/OnVoximplantCallInit.php create mode 100644 src/Services/Telephony/Requests/Events/OnVoximplantCallStart.php diff --git a/src/Services/Telephony/Common/CallType.php b/src/Services/Telephony/Common/CallType.php index 30ac1ce3..acc7d8ab 100644 --- a/src/Services/Telephony/Common/CallType.php +++ b/src/Services/Telephony/Common/CallType.php @@ -25,6 +25,7 @@ class CallType /** * @param int $typeCode + * * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException */ @@ -45,37 +46,65 @@ private function __construct(int $typeCode) /** * @return self */ - public static function outboundCall(): self { return new self(self::OUTBOUND_CALL); } /** - * @return self + * @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 new self(self::INBOUND_CALL); } /** - * @return self + * @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 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 backCall(): self + public static function callback(): self { - return new self( self::CALLBACK); + return new self(self::CALLBACK); + } + + /** + * @return bool + */ + public function isCallback(): bool + { + return $this->code === self::CALLBACK; } public function __toString(): string @@ -83,5 +112,12 @@ 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 index de25f725..99d280a4 100644 --- a/src/Services/Telephony/Common/CrmEntityType.php +++ b/src/Services/Telephony/Common/CrmEntityType.php @@ -24,6 +24,7 @@ class CrmEntityType /** * @param string $typeCode + * * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException */ private function __construct(string $typeCode) @@ -47,6 +48,14 @@ public static function contact(): self return new self(self::CONTACT); } + /** + * @return bool + */ + public function isContact(): bool + { + return $this->code === $this::CONTACT; + } + /** * @return self */ @@ -55,6 +64,14 @@ public static function company(): self return new self(self::COMPANY); } + /** + * @return bool + */ + public function isCompany(): bool + { + return $this->code === $this::COMPANY; + } + /** * @return self */ @@ -63,6 +80,14 @@ public static function lead(): self return new self(self::LEAD); } + /** + * @return bool + */ + public function isLead(): bool + { + return $this->code === $this::LEAD; + } + /** * @return string */ @@ -70,4 +95,12 @@ 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 index dc21a2ed..f3e9a0c7 100644 --- a/src/Services/Telephony/Common/StatusSipCodeInterface.php +++ b/src/Services/Telephony/Common/StatusSipCodeInterface.php @@ -16,88 +16,85 @@ interface StatusSipCodeInterface { //Provisional Responses - const STATUS_TRYING = 100; - const STATUS_RINGING = 180; - const STATUS_CALL_IS_BEING_FORWARDED = 181; - const STATUS_QUEUED = 182; - const STATUS_SESSION_PROGRESS = 183; - const STATUS_EARLY_DIALOG_TERMINATED = 199; + 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 - const STATUS_OK = 200; - const STATUS_ACCEPTED = 202; - const STATUS_NO_NOTIFICATION = 204; + public const STATUS_OK = 200; + public const STATUS_ACCEPTED = 202; + public const STATUS_NO_NOTIFICATION = 204; //Redirection Responses - const STATUS_MULTIPIE_CHOICES = 300; - const STATUS_MOVED_PERMANENTLY = 301; - const STATUS_MOVED_TEMPORARILY = 302; - const STATUS_USE_PROXY = 305; - const STATUS_ALTERNATIVE_SERVICE=380; + 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 - const STATUS_BAD_REQUEST = 400; - const STATUS_UNAUTHORIZED = 401; - const STATUS_PAYMENT_REQUIRED = 402; - const STATUS_FORBIDDEN = 403; - const STATUS_NOT_FOUND = 404; - const STATUS_METHOD_NOT_ALLOWED = 405; - const STATUS_NOT_ACCEPTABLE = 406; - const STATUS_PROXY_AUTHENTICATION_REQUIRED = 407; - const STATUS_REQUEST_TIMEOUT = 408; - const STATUS_C0NFLICT = 409; - const STATUS_GONE = 410; - const STATUS_LENGTH_REQUIRED = 411; - const STATUS_CONDITIONAL_REQUEST_FAILED = 412; - const STATUS_REQUEST_ENTITY_TOO_LARGE = 413; - const STATUS_REQUEST_URI_TOO_LONG = 414; - const STATUS_UNSUPPORTED_MEDIA_TYPE = 415; - const STATUS_UNSUPPORTED_URI_SCHEME = 416; - const STATUS_UNKNOWN_RESOURCE_PRIORITY = 417; - const STATUS_BAD_EXTENSION = 420; - const STATUS_EXTENSION_REQUIRED =421; - const STATUS_SESSION_INTERVAL_TOO_SMALL = 422; - const STATUS_INTERVAL_TOO_BRIED = 423; - const STATUS_BAD_LOCATION_INFORMATION = 424; - const STATUS_BAD_ALERT_MESSAGE = 425; - const STATUS_USE_IDENTITY_HEADER = 428; - const STATUS_PROVIDE_REFERRER_IDENTITY = 429; - const STATUS_FLOW_FAILED = 430; - const STATUS_ANONYMITY_DISALLOWED = 433; - const STATUS_BAD_IDENTITY_INFO = 436; - const STATUS_UNSUPPORTED_CERTIFICATE = 437; - const STATUS_INVALID_IDENTITY_HEADER = 438; - const STATUS_FIRST_HOP_LACKS_OUTBOUND_SUPPORT = 439; - const STATUS_MAX_BREADTH_EXCEEDED = 440; - const STATUS_BAD_INFO_PACKAGE = 469; - const STATUS_CONSENT_NEEDED = 470; - const STATUS_TEMPORARILY_UNAVAILABLE = 480; - const STATUS_CALL_OR_TRANSACTION_DOES_NOT_EXIST = 481; - const STATUS_LOOP_DETECTED = 482; - const STATUS_TOO_MANY_HOPS = 483; - const STATUS_ADDRESS_INCOMPLETE = 484; - const STATUS_AMBIGUOUS = 485; - const STATUS_BUSY_HERE = 486; - const STATUS_REQUEST_TERMINATED = 487; - const STATUS_NOT_ACCEPTABLE_HERE = 488; - const STATUS_BAD_EVENT = 489; - const STATUS_REQUEST_PENDING = 491; - const STATUS_UNDECIPHERABLE = 493; - const STATUS_SECURITY_AGREEMENT_REQUIRED = 494; + 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 - const STATUS_INTERNAL_SERVER_ERROR = 500; - const STATUS_NOT_IMPLEMENTED = 501; - const STATUS_BAD_GATEWAY = 502; - const STATUS_SERVICE_UNAVAILABLE = 503; - const STATUS_SERVER_TIME_OUT = 504; - const STATUS_VERSION_NOT_SUPPORTED = 505; - const STATUS_MESSAGE_TOO_LARGE = 513; - const STATUS_PUSH_NOTIFICATION_SERVICE_NOT_SUPPORTED = 555; - const STATUS_PRECONDITION_FAILURE = 580; + 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 - const STATUS_BUSY_EVERYWHERE = 600; - const STATUS_DECLINE = 603; - const STATUS_DOES_NOT_EXIST_ANYWHERE = 604; - const STATUS_GLOBAL_NOT_ACCEPTABLE = 606; - const STATUS_UNWANTED = 607; - const STATUS_REJECTED = 608; - - + 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/Requests/Events/OnExternalCallBackStart.php b/src/Services/Telephony/Requests/Events/OnExternalCallBackStart.php new file mode 100644 index 00000000..791c5042 --- /dev/null +++ b/src/Services/Telephony/Requests/Events/OnExternalCallBackStart.php @@ -0,0 +1,60 @@ +eventPayload['PHONE_NUMBER']; + } + + /** + * @return string Text to be voiced over to a user during initiated call (). + */ + public function getText(): string + { + return $this->eventPayload['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['VOICE']; + } + + /** + * @return \Bitrix24\SDK\Services\Telephony\Common\CrmEntityType + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public function getCrmEntityType(): CrmEntityType + { + return CrmEntityType::initByCode($this->eventPayload['CRM_ENTITY_TYPE']); + } + + /** + * @return int CRM entity ID with type specified in CRM_ENTITY_TYPE. + */ + public function getCrmEntityId(): int + { + return (int)$this->eventPayload['CRM_ENTITY_ID']; + } + + /** + * @return string Number of external line used to request a callback + */ + public function getLineNumber(): string + { + return $this->eventPayload['LINE_NUMBER']; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Requests/Events/OnExternalCallStart.php b/src/Services/Telephony/Requests/Events/OnExternalCallStart.php new file mode 100644 index 00000000..a7dd87d8 --- /dev/null +++ b/src/Services/Telephony/Requests/Events/OnExternalCallStart.php @@ -0,0 +1,95 @@ +eventPayload['USER_ID']; + } + + /** + * @return string Outbound call ID. + */ + public function getPhoneNumber(): string + { + return $this->eventPayload['PHONE_NUMBER']; + } + + /** + * @return string + */ + public function getPhoneNumberInternational(): string + { + return $this->eventPayload['PHONE_NUMBER_INTERNATIONAL']; + } + + /** + * @return \Bitrix24\SDK\Services\Telephony\Common\CrmEntityType + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public function getCrmEntityType(): CrmEntityType + { + return CrmEntityType::initByCode($this->eventPayload['CRM_ENTITY_TYPE']); + } + + /** + * @return int The CRM object ID, which type is specified in CRM_ENTITY_TYPE. + */ + public function getCrmEntityId(): int + { + return (int)$this->eventPayload['CRM_ENTITY_ID']; + } + + /** + * @return int Call list ID, if the call is made from the call list. + */ + public function getCallListId(): int + { + return (int)$this->eventPayload['CALL_LIST_ID']; + } + + /** + * @return string External line number, via which the the call is requested. + */ + public function getLineNumber(): string + { + return $this->eventPayload['LINE_NUMBER']; + } + + /** + * @return string Call ID from the telephony.externalcall.register method. + */ + public function getCallId(): string + { + return $this->eventPayload['CALL_ID']; + } + + /** + * @return string + */ + public function getExtension(): string + { + return $this->eventPayload['EXTENSION']; + } + + /** + * @return bool Defines call as initiated from the mobile app. + */ + public function isMobile(): bool + { + return !($this->eventPayload['IS_MOBILE'] === '0'); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Requests/Events/OnVoximplantCallEnd.php b/src/Services/Telephony/Requests/Events/OnVoximplantCallEnd.php new file mode 100644 index 00000000..4b6ef544 --- /dev/null +++ b/src/Services/Telephony/Requests/Events/OnVoximplantCallEnd.php @@ -0,0 +1,114 @@ +eventPayload['CALL_ID']; + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public function getCallType(): CallType + { + return CallType::initByTypeCode((int)$this->eventPayload['CALL_TYPE']); + } + + /** + * @return string Number used by the subscriber to make a call (if call type is: 2 – Inbound) or number called by the operator (if call type is: 1 – Outbound). + */ + public function getPhoneNumber(): string + { + return $this->eventPayload['PHONE_NUMBER']; + } + + /** + * @return string Number receiving the call (if call type is: 2 – Inbound) or number from which the call was made (if call type is: 1 – Outbound). + */ + public function getPortalNumber(): string + { + return $this->eventPayload['PORTAL_NUMBER']; + } + + /** + * @return int Responding operator ID (if call type is: 2 – Inbound) or identifier of the calling operator (if call type is: 1 – Outbound). + */ + public function getPortalUserId(): int + { + return (int)$this->eventPayload['PORTAL_USER_ID']; + } + + /** + * @return int Call duration. + */ + public function getCallDuration(): int + { + return (int)$this->eventPayload['CALL_DURATION']; + } + + /** + * @return \DateTimeImmutable Date in ISO format. + */ + public function getCallStartDate(): DateTimeImmutable + { + return DateTimeImmutable::createFromFormat(DATE_ATOM, $this->eventPayload['CALL_START_DATE']); + } + + /** + * @return \Money\Money Call cost. + */ + public function getCost(): Money + { + if ($this->eventPayload['COST'] === '') { + return new Money(0, new Currency($this->eventPayload['COST_CURRENCY'])); + } + + return (new DecimalMoneyParser(new ISOCurrencies()))->parse( + $this->eventPayload['COST'], + $this->eventPayload['COST_CURRENCY'] + ); + } + + /** + * @return int Call code (See Call Code Table). + */ + public function getCallFailedCode(): int + { + return (int)$this->eventPayload['CALL_FAILED_CODE']; + } + + /** + * @return string Call code textual description (Latin letters). + */ + public function getCallFailedReason(): string + { + return $this->eventPayload['CALL_FAILED_REASON']; + } + + /** + * @return int + */ + public function getCrmActivityId(): int + { + return (int)$this->eventPayload['CRM_ACTIVITY_ID']; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Requests/Events/OnVoximplantCallInit.php b/src/Services/Telephony/Requests/Events/OnVoximplantCallInit.php new file mode 100644 index 00000000..3711dfb6 --- /dev/null +++ b/src/Services/Telephony/Requests/Events/OnVoximplantCallInit.php @@ -0,0 +1,54 @@ +eventPayload['CALL_ID']; + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public function getCallType(): CallType + { + return CallType::initByTypeCode((int)$this->eventPayload['CALL_TYPE']); + } + + /** + * @return string Line ID (numeric for leased PBX, regXXX for cloud hosted PBX, and sipXXX for office PBX). + */ + public function getAccountSearchId(): string + { + return $this->eventPayload['ACCOUNT_SEARCH_ID']; + } + + /** + * @return string Number called by the operator (if call type is: 1 – Outbound) or number called by the subscriber (if call type is: 2 – Inbound). + */ + public function getPhoneNumber(): string + { + return $this->eventPayload['PHONE_NUMBER']; + } + + /** + * @return string Line identifier (if call type is: 1 – Outbound) or telephone number used to make a call to the portal (if call type is: 2 – Inbound). + */ + public function getCallerId(): string + { + return $this->eventPayload['CALLER_ID']; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Requests/Events/OnVoximplantCallStart.php b/src/Services/Telephony/Requests/Events/OnVoximplantCallStart.php new file mode 100644 index 00000000..26278b82 --- /dev/null +++ b/src/Services/Telephony/Requests/Events/OnVoximplantCallStart.php @@ -0,0 +1,29 @@ +eventPayload['CALL_ID']; + } + + /** + * @return int Identifier of the user who responded the call. + */ + public function getUserId(): int + { + return (int)$this->eventPayload['USER_ID']; + } +} \ No newline at end of file From 3d36163f9a2938e804e88f2db2c9693bea566962 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 28 Jul 2022 15:06:07 +0300 Subject: [PATCH 405/647] bump CHANGELOG.md Signed-off-by: mesilov --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c44ccf7b..a8a8b5dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,8 @@ integration test * add method to interface `Core\Contracts\BatchInterface::updateEntityItems` for update items in batch mode * add in scope `Placements` service `Placement\Service\UserFieldType` for work with user fields embedding +* add in scope `Telephony` add events: `OnExternalCallBackStart`, `OnExternalCallStart`, `OnVoximplantCallEnd`, `OnVoximplantCallEnd` + , `OnVoximplantCallInit`, `OnVoximplantCallStart` see [add telephony events](https://github.com/mesilov/bitrix24-php-sdk/issues/304) * add `ApplicationStatus` with application status codes description * add fabric method `AccessToken::initFromPlacementRequest` when application init form placement request * add fabric method `ApplicationProfile::initFromArray` when application profile stored in ENV-variables From 43ed959137701aa38d0f8bba48d1c25dbf13154a Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 28 Jul 2022 16:01:44 +0300 Subject: [PATCH 406/647] fix offset Signed-off-by: mesilov --- .../Events/OnExternalCallBackStart.php | 12 ++++----- .../Requests/Events/OnExternalCallStart.php | 20 +++++++------- .../Requests/Events/OnVoximplantCallEnd.php | 26 +++++++++---------- .../Requests/Events/OnVoximplantCallInit.php | 10 +++---- .../Requests/Events/OnVoximplantCallStart.php | 4 +-- 5 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/Services/Telephony/Requests/Events/OnExternalCallBackStart.php b/src/Services/Telephony/Requests/Events/OnExternalCallBackStart.php index 791c5042..7582e152 100644 --- a/src/Services/Telephony/Requests/Events/OnExternalCallBackStart.php +++ b/src/Services/Telephony/Requests/Events/OnExternalCallBackStart.php @@ -14,7 +14,7 @@ class OnExternalCallBackStart extends AbstractEventRequest */ public function getPhoneNumber(): string { - return $this->eventPayload['PHONE_NUMBER']; + return $this->eventPayload['data']['PHONE_NUMBER']; } /** @@ -22,7 +22,7 @@ public function getPhoneNumber(): string */ public function getText(): string { - return $this->eventPayload['TEXT']; + return $this->eventPayload['data']['TEXT']; } /** @@ -30,7 +30,7 @@ public function getText(): string */ public function getVoiceId(): string { - return $this->eventPayload['VOICE']; + return $this->eventPayload['data']['VOICE']; } /** @@ -39,7 +39,7 @@ public function getVoiceId(): string */ public function getCrmEntityType(): CrmEntityType { - return CrmEntityType::initByCode($this->eventPayload['CRM_ENTITY_TYPE']); + return CrmEntityType::initByCode($this->eventPayload['data']['CRM_ENTITY_TYPE']); } /** @@ -47,7 +47,7 @@ public function getCrmEntityType(): CrmEntityType */ public function getCrmEntityId(): int { - return (int)$this->eventPayload['CRM_ENTITY_ID']; + return (int)$this->eventPayload['data']['CRM_ENTITY_ID']; } /** @@ -55,6 +55,6 @@ public function getCrmEntityId(): int */ public function getLineNumber(): string { - return $this->eventPayload['LINE_NUMBER']; + return $this->eventPayload['data']['LINE_NUMBER']; } } \ No newline at end of file diff --git a/src/Services/Telephony/Requests/Events/OnExternalCallStart.php b/src/Services/Telephony/Requests/Events/OnExternalCallStart.php index a7dd87d8..6361a3c1 100644 --- a/src/Services/Telephony/Requests/Events/OnExternalCallStart.php +++ b/src/Services/Telephony/Requests/Events/OnExternalCallStart.php @@ -17,7 +17,7 @@ class OnExternalCallStart extends AbstractEventRequest */ public function getUserId(): int { - return (int)$this->eventPayload['USER_ID']; + return (int)$this->eventPayload['data']['USER_ID']; } /** @@ -25,7 +25,7 @@ public function getUserId(): int */ public function getPhoneNumber(): string { - return $this->eventPayload['PHONE_NUMBER']; + return $this->eventPayload['data']['PHONE_NUMBER']; } /** @@ -33,7 +33,7 @@ public function getPhoneNumber(): string */ public function getPhoneNumberInternational(): string { - return $this->eventPayload['PHONE_NUMBER_INTERNATIONAL']; + return $this->eventPayload['data']['PHONE_NUMBER_INTERNATIONAL']; } /** @@ -42,7 +42,7 @@ public function getPhoneNumberInternational(): string */ public function getCrmEntityType(): CrmEntityType { - return CrmEntityType::initByCode($this->eventPayload['CRM_ENTITY_TYPE']); + return CrmEntityType::initByCode($this->eventPayload['data']['CRM_ENTITY_TYPE']); } /** @@ -50,7 +50,7 @@ public function getCrmEntityType(): CrmEntityType */ public function getCrmEntityId(): int { - return (int)$this->eventPayload['CRM_ENTITY_ID']; + return (int)$this->eventPayload['data']['CRM_ENTITY_ID']; } /** @@ -58,7 +58,7 @@ public function getCrmEntityId(): int */ public function getCallListId(): int { - return (int)$this->eventPayload['CALL_LIST_ID']; + return (int)$this->eventPayload['data']['CALL_LIST_ID']; } /** @@ -66,7 +66,7 @@ public function getCallListId(): int */ public function getLineNumber(): string { - return $this->eventPayload['LINE_NUMBER']; + return $this->eventPayload['data']['LINE_NUMBER']; } /** @@ -74,7 +74,7 @@ public function getLineNumber(): string */ public function getCallId(): string { - return $this->eventPayload['CALL_ID']; + return $this->eventPayload['data']['CALL_ID']; } /** @@ -82,7 +82,7 @@ public function getCallId(): string */ public function getExtension(): string { - return $this->eventPayload['EXTENSION']; + return $this->eventPayload['data']['EXTENSION']; } /** @@ -90,6 +90,6 @@ public function getExtension(): string */ public function isMobile(): bool { - return !($this->eventPayload['IS_MOBILE'] === '0'); + return !($this->eventPayload['data']['IS_MOBILE'] === '0'); } } \ No newline at end of file diff --git a/src/Services/Telephony/Requests/Events/OnVoximplantCallEnd.php b/src/Services/Telephony/Requests/Events/OnVoximplantCallEnd.php index 4b6ef544..ff0229f4 100644 --- a/src/Services/Telephony/Requests/Events/OnVoximplantCallEnd.php +++ b/src/Services/Telephony/Requests/Events/OnVoximplantCallEnd.php @@ -22,7 +22,7 @@ class OnVoximplantCallEnd extends AbstractEventRequest */ public function getCallId(): string { - return $this->eventPayload['CALL_ID']; + return $this->eventPayload['data']['CALL_ID']; } /** @@ -30,7 +30,7 @@ public function getCallId(): string */ public function getCallType(): CallType { - return CallType::initByTypeCode((int)$this->eventPayload['CALL_TYPE']); + return CallType::initByTypeCode((int)$this->eventPayload['data']['CALL_TYPE']); } /** @@ -38,7 +38,7 @@ public function getCallType(): CallType */ public function getPhoneNumber(): string { - return $this->eventPayload['PHONE_NUMBER']; + return $this->eventPayload['data']['PHONE_NUMBER']; } /** @@ -46,7 +46,7 @@ public function getPhoneNumber(): string */ public function getPortalNumber(): string { - return $this->eventPayload['PORTAL_NUMBER']; + return $this->eventPayload['data']['PORTAL_NUMBER']; } /** @@ -54,7 +54,7 @@ public function getPortalNumber(): string */ public function getPortalUserId(): int { - return (int)$this->eventPayload['PORTAL_USER_ID']; + return (int)$this->eventPayload['data']['PORTAL_USER_ID']; } /** @@ -62,7 +62,7 @@ public function getPortalUserId(): int */ public function getCallDuration(): int { - return (int)$this->eventPayload['CALL_DURATION']; + return (int)$this->eventPayload['data']['CALL_DURATION']; } /** @@ -70,7 +70,7 @@ public function getCallDuration(): int */ public function getCallStartDate(): DateTimeImmutable { - return DateTimeImmutable::createFromFormat(DATE_ATOM, $this->eventPayload['CALL_START_DATE']); + return DateTimeImmutable::createFromFormat(DATE_ATOM, $this->eventPayload['data']['CALL_START_DATE']); } /** @@ -79,12 +79,12 @@ public function getCallStartDate(): DateTimeImmutable public function getCost(): Money { if ($this->eventPayload['COST'] === '') { - return new Money(0, new Currency($this->eventPayload['COST_CURRENCY'])); + return new Money(0, new Currency($this->eventPayload['data']['COST_CURRENCY'])); } return (new DecimalMoneyParser(new ISOCurrencies()))->parse( - $this->eventPayload['COST'], - $this->eventPayload['COST_CURRENCY'] + $this->eventPayload['data']['COST'], + $this->eventPayload['data']['COST_CURRENCY'] ); } @@ -93,7 +93,7 @@ public function getCost(): Money */ public function getCallFailedCode(): int { - return (int)$this->eventPayload['CALL_FAILED_CODE']; + return (int)$this->eventPayload['data']['CALL_FAILED_CODE']; } /** @@ -101,7 +101,7 @@ public function getCallFailedCode(): int */ public function getCallFailedReason(): string { - return $this->eventPayload['CALL_FAILED_REASON']; + return $this->eventPayload['data']['CALL_FAILED_REASON']; } /** @@ -109,6 +109,6 @@ public function getCallFailedReason(): string */ public function getCrmActivityId(): int { - return (int)$this->eventPayload['CRM_ACTIVITY_ID']; + return (int)$this->eventPayload['data']['CRM_ACTIVITY_ID']; } } \ No newline at end of file diff --git a/src/Services/Telephony/Requests/Events/OnVoximplantCallInit.php b/src/Services/Telephony/Requests/Events/OnVoximplantCallInit.php index 3711dfb6..753f2d67 100644 --- a/src/Services/Telephony/Requests/Events/OnVoximplantCallInit.php +++ b/src/Services/Telephony/Requests/Events/OnVoximplantCallInit.php @@ -17,7 +17,7 @@ class OnVoximplantCallInit extends AbstractEventRequest */ public function getCallId(): string { - return $this->eventPayload['CALL_ID']; + return $this->eventPayload['data']['CALL_ID']; } /** @@ -25,7 +25,7 @@ public function getCallId(): string */ public function getCallType(): CallType { - return CallType::initByTypeCode((int)$this->eventPayload['CALL_TYPE']); + return CallType::initByTypeCode((int)$this->eventPayload['data']['CALL_TYPE']); } /** @@ -33,7 +33,7 @@ public function getCallType(): CallType */ public function getAccountSearchId(): string { - return $this->eventPayload['ACCOUNT_SEARCH_ID']; + return $this->eventPayload['data']['ACCOUNT_SEARCH_ID']; } /** @@ -41,7 +41,7 @@ public function getAccountSearchId(): string */ public function getPhoneNumber(): string { - return $this->eventPayload['PHONE_NUMBER']; + return $this->eventPayload['data']['PHONE_NUMBER']; } /** @@ -49,6 +49,6 @@ public function getPhoneNumber(): string */ public function getCallerId(): string { - return $this->eventPayload['CALLER_ID']; + return $this->eventPayload['data']['CALLER_ID']; } } \ No newline at end of file diff --git a/src/Services/Telephony/Requests/Events/OnVoximplantCallStart.php b/src/Services/Telephony/Requests/Events/OnVoximplantCallStart.php index 26278b82..11df4201 100644 --- a/src/Services/Telephony/Requests/Events/OnVoximplantCallStart.php +++ b/src/Services/Telephony/Requests/Events/OnVoximplantCallStart.php @@ -16,7 +16,7 @@ class OnVoximplantCallStart extends AbstractEventRequest */ public function getCallId(): string { - return $this->eventPayload['CALL_ID']; + return $this->eventPayload['data']['CALL_ID']; } /** @@ -24,6 +24,6 @@ public function getCallId(): string */ public function getUserId(): int { - return (int)$this->eventPayload['USER_ID']; + return (int)$this->eventPayload['data']['USER_ID']; } } \ No newline at end of file From 6a2c05d4f53af2f6c941cee792c79e1aed5f928f Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 31 Jul 2022 01:26:37 +0300 Subject: [PATCH 407/647] add open lines support Signed-off-by: mesilov --- CHANGELOG.md | 1 + .../IMOpenLines/IMOpenLinesServiceBuilder.php | 23 ++++++ .../Result/AddedMessageItemResult.php | 21 ++++++ .../IMOpenLines/Result/JoinOpenLineResult.php | 20 ++++++ src/Services/IMOpenLines/Service/Network.php | 71 +++++++++++++++++++ src/Services/ServiceBuilder.php | 13 ++++ tests/.env | 4 +- tests/Integration/Fabric.php | 8 +++ .../IMOpenLines/Service/NetworkTest.php | 50 +++++++++++++ 9 files changed, 210 insertions(+), 1 deletion(-) create mode 100644 src/Services/IMOpenLines/IMOpenLinesServiceBuilder.php create mode 100644 src/Services/IMOpenLines/Result/AddedMessageItemResult.php create mode 100644 src/Services/IMOpenLines/Result/JoinOpenLineResult.php create mode 100644 src/Services/IMOpenLines/Service/Network.php create mode 100644 tests/Integration/Services/IMOpenLines/Service/NetworkTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index a8a8b5dd..ab70c013 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ * add new scope `Telephony` and services [add Telephony support](https://github.com/mesilov/bitrix24-php-sdk/issues/291) * add new scope `UserConsent` and services [add UserConsent support](https://github.com/mesilov/bitrix24-php-sdk/issues/285) * add new scope `Placements` and services [add Placements support](https://github.com/mesilov/bitrix24-php-sdk/issues/274) +* add new scope `IMOpenLines` and services [add IM Open Lines support](https://github.com/mesilov/bitrix24-php-sdk/issues/302) * add in scope `CRM` new service `Leads` in scope «CRM» [add Leads support](https://github.com/mesilov/bitrix24-php-sdk/issues/282) * add in scope `CRM` new service `Activity` in scope «CRM» [add Activity support](https://github.com/mesilov/bitrix24-php-sdk/issues/283) * add in scope `CRM` for entity Deal method `Services\CRM\Deal\Service\Batch::update` batch update deals diff --git a/src/Services/IMOpenLines/IMOpenLinesServiceBuilder.php b/src/Services/IMOpenLines/IMOpenLinesServiceBuilder.php new file mode 100644 index 00000000..e5e198b8 --- /dev/null +++ b/src/Services/IMOpenLines/IMOpenLinesServiceBuilder.php @@ -0,0 +1,23 @@ +serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Network($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } +} \ No newline at end of file diff --git a/src/Services/IMOpenLines/Result/AddedMessageItemResult.php b/src/Services/IMOpenLines/Result/AddedMessageItemResult.php new file mode 100644 index 00000000..b381263e --- /dev/null +++ b/src/Services/IMOpenLines/Result/AddedMessageItemResult.php @@ -0,0 +1,21 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + } +} \ No newline at end of file diff --git a/src/Services/IMOpenLines/Result/JoinOpenLineResult.php b/src/Services/IMOpenLines/Result/JoinOpenLineResult.php new file mode 100644 index 00000000..2254051b --- /dev/null +++ b/src/Services/IMOpenLines/Result/JoinOpenLineResult.php @@ -0,0 +1,20 @@ +getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + } +} \ No newline at end of file diff --git a/src/Services/IMOpenLines/Service/Network.php b/src/Services/IMOpenLines/Service/Network.php new file mode 100644 index 00000000..b99fdfca --- /dev/null +++ b/src/Services/IMOpenLines/Service/Network.php @@ -0,0 +1,71 @@ +core->call( + 'imopenlines.network.join', + [ + 'CODE' => $openLineCode, + ] + ) + ); + } + + /** + * Sending Open Channel message to selected user + * + * @param string $openLineCode + * @param int $recipientUserId + * @param string $message + * @param bool $isMakeUrlPreview + * @param array|null $attach + * @param array|null $keyboard + * + * @return AddedMessageItemResult + * @link https://training.bitrix24.com/support/training/course/?COURSE_ID=115&LESSON_ID=25018&LESSON_PATH=9691.9833.20331.25014.25018 + * + */ + public function messageAdd( + string $openLineCode, + int $recipientUserId, + string $message, + bool $isMakeUrlPreview = true, + ?array $attach = null, + ?array $keyboard = null + ): AddedMessageItemResult { + return new AddedMessageItemResult( + $this->core->call( + 'imopenlines.network.message.add', + [ + 'CODE' => $openLineCode, + 'USER_ID' => $recipientUserId, + 'MESSAGE' => $message, + 'URL_PREVIEW' => $isMakeUrlPreview ? 'Y' : 'N', + 'ATTACH' => $attach, + 'KEYBOARD' => $keyboard, + ] + ) + ); + } +} \ No newline at end of file diff --git a/src/Services/ServiceBuilder.php b/src/Services/ServiceBuilder.php index 830cd9dd..ecc0cac0 100644 --- a/src/Services/ServiceBuilder.php +++ b/src/Services/ServiceBuilder.php @@ -6,6 +6,7 @@ use Bitrix24\SDK\Services\CRM\CRMServiceBuilder; use Bitrix24\SDK\Services\IM\IMServiceBuilder; +use Bitrix24\SDK\Services\IMOpenLines\IMOpenLinesServiceBuilder; use Bitrix24\SDK\Services\Main\MainServiceBuilder; use Bitrix24\SDK\Services\Telephony\TelephonyServiceBuilder; use Bitrix24\SDK\Services\UserConsent\UserConsentServiceBuilder; @@ -42,6 +43,18 @@ public function getIMScope(): IMServiceBuilder return $this->serviceCache[__METHOD__]; } + /** + * @return IMOpenLinesServiceBuilder + */ + public function getIMOpenLinesScope(): IMOpenLinesServiceBuilder + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new IMOpenLinesServiceBuilder($this->core, $this->batch, $this->bulkItemsReader, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + /** * @return MainServiceBuilder */ diff --git a/tests/.env b/tests/.env index 481d15ae..6fc806a2 100644 --- a/tests/.env +++ b/tests/.env @@ -18,4 +18,6 @@ APP_ENV=dev BITRIX24_WEBHOOK= # monolog log level -INTEGRATION_TEST_LOG_LEVEL=200 \ No newline at end of file +INTEGRATION_TEST_LOG_LEVEL=200 +# integration tests assets +INTEGRATION_TEST_OPEN_LINE_CODE=40863c519996e505b5cde98749c97413 \ No newline at end of file diff --git a/tests/Integration/Fabric.php b/tests/Integration/Fabric.php index dcf0e876..881e6569 100644 --- a/tests/Integration/Fabric.php +++ b/tests/Integration/Fabric.php @@ -32,6 +32,14 @@ public static function getServiceBuilder(): ServiceBuilder return new ServiceBuilder(self::getCore(), self::getBatchService(), self::getBulkItemsReader(), self::getLogger()); } + /** + * @return string + */ + public static function getOpenLineCode(): string + { + return (string)$_ENV['INTEGRATION_TEST_OPEN_LINE_CODE']; + } + /** * @return \Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException diff --git a/tests/Integration/Services/IMOpenLines/Service/NetworkTest.php b/tests/Integration/Services/IMOpenLines/Service/NetworkTest.php new file mode 100644 index 00000000..50c9a76e --- /dev/null +++ b/tests/Integration/Services/IMOpenLines/Service/NetworkTest.php @@ -0,0 +1,50 @@ +networkService->join(Fabric::getOpenLineCode()); + $this->assertGreaterThanOrEqual(1, $res->getId()); + } + + /** + * @covers \Bitrix24\SDK\Services\IMOpenLines\Service\Network::join + * @testdox test get agreements list + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function testMessageAdd(): void + { + $res = $this->networkService->messageAdd( + Fabric::getOpenLineCode(), + (int)$this->networkService->core->call('PROFILE')->getResponseData()->getResult()->getResultData()['ID'], + sprintf('Test message at %s', time()) + ); + + $this->assertTrue($res->isSuccess()); + } + + public function setUp(): void + { + $this->networkService = Fabric::getServiceBuilder()->getIMOpenLinesScope()->Network(); + } +} \ No newline at end of file From 88c5faad9a0b03b2174ddb3903d805824bda6af7 Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 3 Aug 2022 01:13:48 +0300 Subject: [PATCH 408/647] fix Credentials.php Signed-off-by: mesilov --- CHANGELOG.md | 2 ++ src/Core/CoreBuilder.php | 4 +++- src/Core/Credentials/Credentials.php | 8 ++++---- tests/Unit/Core/Credentials/CredentialsTest.php | 10 +++++----- tests/Unit/Stubs/NullCore.php | 2 +- 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab70c013..f7206e3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,8 @@ * method `Services\Main\Service::getAvailableMethods` marks as deprecated * method `Services\Main\Service::getAllMethods` marks as deprecated * method `Services\Main\Service::getMethodsByScope` marks as deprecated +* fabric methods for `Bitrix24\SDK\Core\Credentials` + are [consistent](https://github.com/mesilov/bitrix24-php-sdk/issues/303): `createFromWebhook`, `createFromOAuth`, `createFromPlacementRequest` ### Bugfix diff --git a/src/Core/CoreBuilder.php b/src/Core/CoreBuilder.php index 1d2175a4..efb19a55 100644 --- a/src/Core/CoreBuilder.php +++ b/src/Core/CoreBuilder.php @@ -66,6 +66,8 @@ public function withCredentials(Credentials $credentials): self * @param string $webhookUrl * * @return $this + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @deprecated use withCredentials */ public function withWebhookUrl(string $webhookUrl): self { @@ -117,7 +119,7 @@ public function withEventDispatcher(EventDispatcherInterface $eventDispatcher): public function build(): CoreInterface { if ($this->webhookUrl !== null) { - $this->credentials = Credentials::createForWebHook($this->webhookUrl); + $this->credentials = Credentials::createFromWebhook($this->webhookUrl); } elseif ($this->credentials === null) { throw new InvalidArgumentException('you must set webhook url or oauth credentials before call method build'); } diff --git a/src/Core/Credentials/Credentials.php b/src/Core/Credentials/Credentials.php index 2f38633e..54260ac6 100644 --- a/src/Core/Credentials/Credentials.php +++ b/src/Core/Credentials/Credentials.php @@ -124,7 +124,7 @@ public function getAccessToken(): ?AccessToken * @return self * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException */ - public static function createForWebHook(WebhookUrl $webhookUrl): self + public static function createFromWebhook(WebhookUrl $webhookUrl): self { return new self( $webhookUrl, @@ -142,7 +142,7 @@ public static function createForWebHook(WebhookUrl $webhookUrl): self * @return self * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException */ - public static function createForOAuth(AccessToken $accessToken, ApplicationProfile $applicationProfile, string $domainUrl): self + public static function createFromOAuth(AccessToken $accessToken, ApplicationProfile $applicationProfile, string $domainUrl): self { return new self( null, @@ -159,9 +159,9 @@ public static function createForOAuth(AccessToken $accessToken, ApplicationProfi * @return self * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException */ - public static function initFromPlacementRequest(PlacementRequest $placementRequest, ApplicationProfile $applicationProfile): self + public static function createFromPlacementRequest(PlacementRequest $placementRequest, ApplicationProfile $applicationProfile): self { - return self::createForOAuth( + return self::createFromOAuth( $placementRequest->getAccessToken(), $applicationProfile, $placementRequest->getDomainUrl() diff --git a/tests/Unit/Core/Credentials/CredentialsTest.php b/tests/Unit/Core/Credentials/CredentialsTest.php index 2d061673..5d3ccfdb 100644 --- a/tests/Unit/Core/Credentials/CredentialsTest.php +++ b/tests/Unit/Core/Credentials/CredentialsTest.php @@ -36,7 +36,7 @@ public function testGetDomainUrl( */ public function testDomainUrlWithoutProtocol(): void { - $credentials = Credentials::createForOAuth( + $credentials = Credentials::createFromOAuth( new AccessToken('', '', 0), new ApplicationProfile('', '', new Scope(['crm'])), 'bitrix24-php-sdk-playground.bitrix24.ru' @@ -54,7 +54,7 @@ public function testDomainUrlWithoutProtocol(): void */ public function testDomainUrlWithProtocol(): void { - $credentials = Credentials::createForOAuth( + $credentials = Credentials::createFromOAuth( new AccessToken('', '', 0), new ApplicationProfile('', '', new Scope(['crm'])), 'https://bitrix24-php-sdk-playground.bitrix24.ru' @@ -73,11 +73,11 @@ public function testDomainUrlWithProtocol(): void public function credentialsDataProviderWithDomainUrlVariants(): Generator { yield 'with webhook walid domain url' => [ - Credentials::createForWebHook(new WebhookUrl('https://bitrix24-php-sdk-playground.bitrix24.ru/rest/1/valid-webhook/')), + Credentials::createFromWebhook(new WebhookUrl('https://bitrix24-php-sdk-playground.bitrix24.ru/rest/1/valid-webhook/')), 'https://bitrix24-php-sdk-playground.bitrix24.ru', ]; yield 'with oauth domain url with end /' => [ - Credentials::createForOAuth( + Credentials::createFromOAuth( new AccessToken('', '', 0), new ApplicationProfile('', '', new Scope(['crm'])), 'https://bitrix24-php-sdk-playground.bitrix24.ru/' @@ -85,7 +85,7 @@ public function credentialsDataProviderWithDomainUrlVariants(): Generator 'https://bitrix24-php-sdk-playground.bitrix24.ru', ]; yield 'with oauth domain url without end /' => [ - Credentials::createForOAuth( + Credentials::createFromOAuth( new AccessToken('', '', 0), new ApplicationProfile('', '', new Scope(['crm'])), 'https://bitrix24-php-sdk-playground.bitrix24.ru' diff --git a/tests/Unit/Stubs/NullCore.php b/tests/Unit/Stubs/NullCore.php index 494c0c3e..493da934 100644 --- a/tests/Unit/Stubs/NullCore.php +++ b/tests/Unit/Stubs/NullCore.php @@ -36,6 +36,6 @@ public function call(string $apiMethod, array $parameters = []): Response public function getApiClient(): ApiClientInterface { - return new ApiClient(Credentials::createForWebHook(new WebhookUrl('')), new MockHttpClient(), new NullLogger()); + return new ApiClient(Credentials::createFromWebhook(new WebhookUrl('')), new MockHttpClient(), new NullLogger()); } } \ No newline at end of file From 60a8a7bcd7dda3f13213c195bbf54b8aca79affc Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 3 Aug 2022 01:16:39 +0300 Subject: [PATCH 409/647] deleted unused ResponseDataCollection.php Signed-off-by: mesilov --- CHANGELOG.md | 2 ++ .../Response/DTO/ResponseDataCollection.php | 18 ------------------ 2 files changed, 2 insertions(+), 18 deletions(-) delete mode 100644 src/Core/Response/DTO/ResponseDataCollection.php diff --git a/CHANGELOG.md b/CHANGELOG.md index f7206e3b..d849c1ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,8 @@ * method `Services\Main\Service::getMethodsByScope` marks as deprecated * fabric methods for `Bitrix24\SDK\Core\Credentials` 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` + ### Bugfix diff --git a/src/Core/Response/DTO/ResponseDataCollection.php b/src/Core/Response/DTO/ResponseDataCollection.php deleted file mode 100644 index da7d35f3..00000000 --- a/src/Core/Response/DTO/ResponseDataCollection.php +++ /dev/null @@ -1,18 +0,0 @@ - Date: Wed, 3 Aug 2022 01:33:26 +0300 Subject: [PATCH 410/647] fix withCredentials method Signed-off-by: mesilov --- CHANGELOG.md | 6 ++- src/Core/CoreBuilder.php | 22 +---------- tests/Integration/Fabric.php | 3 +- tests/Unit/Core/CoreBuilderTest.php | 39 +++++++++++++++++++ .../CRM/Contacts/GenerateContactsCommand.php | 4 +- tools/PerformanceBenchmarks/ListCommand.php | 4 +- tools/ShowFieldsDescriptionCommand.php | 7 +++- 7 files changed, 58 insertions(+), 27 deletions(-) create mode 100644 tests/Unit/Core/CoreBuilderTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index d849c1ac..17f4e290 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,9 +46,11 @@ * method `Services\Main\Service::getAllMethods` marks as deprecated * method `Services\Main\Service::getMethodsByScope` marks as deprecated * fabric methods for `Bitrix24\SDK\Core\Credentials` - are [consistent](https://github.com/mesilov/bitrix24-php-sdk/issues/303): `createFromWebhook`, `createFromOAuth`, `createFromPlacementRequest` + 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 [method](https://github.com/mesilov/bitrix24-php-sdk/issues/303) `CoreBuilder::withWebhookUrl`, use + method `CoreBuilder::withCredentials` ### Bugfix diff --git a/src/Core/CoreBuilder.php b/src/Core/CoreBuilder.php index efb19a55..e188ae62 100644 --- a/src/Core/CoreBuilder.php +++ b/src/Core/CoreBuilder.php @@ -27,7 +27,6 @@ class CoreBuilder protected HttpClientInterface $httpClient; protected EventDispatcherInterface $eventDispatcher; protected LoggerInterface $logger; - protected ?WebhookUrl $webhookUrl; protected ?Credentials $credentials; protected ApiLevelErrorHandler $apiLevelErrorHandler; @@ -44,7 +43,6 @@ public function __construct() 'timeout' => 120, ] ); - $this->webhookUrl = null; $this->credentials = null; $this->apiClient = null; $this->apiLevelErrorHandler = new ApiLevelErrorHandler($this->logger); @@ -62,20 +60,6 @@ public function withCredentials(Credentials $credentials): self return $this; } - /** - * @param string $webhookUrl - * - * @return $this - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException - * @deprecated use withCredentials - */ - public function withWebhookUrl(string $webhookUrl): self - { - $this->webhookUrl = new WebhookUrl($webhookUrl); - - return $this; - } - /** * @param ApiClientInterface $apiClient * @@ -118,10 +102,8 @@ public function withEventDispatcher(EventDispatcherInterface $eventDispatcher): */ public function build(): CoreInterface { - if ($this->webhookUrl !== null) { - $this->credentials = Credentials::createFromWebhook($this->webhookUrl); - } elseif ($this->credentials === null) { - throw new InvalidArgumentException('you must set webhook url or oauth credentials before call method build'); + if ($this->credentials === null) { + throw new InvalidArgumentException('you must set credentials before call method build'); } if ($this->apiClient === null) { diff --git a/tests/Integration/Fabric.php b/tests/Integration/Fabric.php index 881e6569..7fcf7736 100644 --- a/tests/Integration/Fabric.php +++ b/tests/Integration/Fabric.php @@ -9,6 +9,7 @@ use Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface; use Bitrix24\SDK\Core\Contracts\CoreInterface; use Bitrix24\SDK\Core\CoreBuilder; +use Bitrix24\SDK\Core\Credentials\Credentials; use Bitrix24\SDK\Services\ServiceBuilder; use Monolog\Handler\StreamHandler; use Monolog\Logger; @@ -57,7 +58,7 @@ public static function getCore(): CoreInterface { return (new CoreBuilder()) ->withLogger(self::getLogger()) - ->withWebhookUrl($_ENV['BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK'] ?? $_ENV['BITRIX24_WEBHOOK']) + ->withCredentials(Credentials::createFromWebhook($_ENV['BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK'] ?? $_ENV['BITRIX24_WEBHOOK'])) ->build(); } diff --git a/tests/Unit/Core/CoreBuilderTest.php b/tests/Unit/Core/CoreBuilderTest.php new file mode 100644 index 00000000..33ffa331 --- /dev/null +++ b/tests/Unit/Core/CoreBuilderTest.php @@ -0,0 +1,39 @@ +withCredentials(Credentials::createFromWebhook(new WebhookUrl('https://127.0.0.1'))) + ->build(); + // successful build core + $this->assertTrue(true); + } + + /** + * @throws UnknownScopeCodeException + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public function testBuildWithoutCredentials(): void + { + $this->expectException(InvalidArgumentException::class); + $core = (new CoreBuilder()) + ->build(); + } +} diff --git a/tools/DemoDataGenerators/CRM/Contacts/GenerateContactsCommand.php b/tools/DemoDataGenerators/CRM/Contacts/GenerateContactsCommand.php index 1a37e3a9..baaa96b4 100644 --- a/tools/DemoDataGenerators/CRM/Contacts/GenerateContactsCommand.php +++ b/tools/DemoDataGenerators/CRM/Contacts/GenerateContactsCommand.php @@ -7,6 +7,8 @@ use Bitrix24\SDK\Core\Batch; use Bitrix24\SDK\Core\BulkItemsReader\BulkItemsReaderBuilder; use Bitrix24\SDK\Core\CoreBuilder; +use Bitrix24\SDK\Core\Credentials\Credentials; +use Bitrix24\SDK\Core\Credentials\WebhookUrl; use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Services\ServiceBuilder; use InvalidArgumentException; @@ -114,7 +116,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int // todo create service builder factory $core = (new CoreBuilder()) ->withLogger($this->logger) - ->withWebhookUrl($b24Webhook) + ->withCredentials(Credentials::createFromWebhook(new WebhookUrl($b24Webhook))) ->build(); $batch = new Batch( $core, diff --git a/tools/PerformanceBenchmarks/ListCommand.php b/tools/PerformanceBenchmarks/ListCommand.php index 309d98fc..1a5d06f7 100644 --- a/tools/PerformanceBenchmarks/ListCommand.php +++ b/tools/PerformanceBenchmarks/ListCommand.php @@ -8,6 +8,8 @@ use Bitrix24\SDK\Core\Contracts\BatchInterface; use Bitrix24\SDK\Core\Contracts\CoreInterface; use Bitrix24\SDK\Core\CoreBuilder; +use Bitrix24\SDK\Core\Credentials\Credentials; +use Bitrix24\SDK\Core\Credentials\WebhookUrl; use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Exceptions\TransportException; use Psr\Log\LoggerInterface; @@ -147,7 +149,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->core = (new CoreBuilder()) ->withLogger($this->logger) - ->withWebhookUrl($b24Webhook) + ->withCredentials(Credentials::createFromWebhook(new WebhookUrl($b24Webhook))) ->build(); $this->batch = new Batch( $this->core, diff --git a/tools/ShowFieldsDescriptionCommand.php b/tools/ShowFieldsDescriptionCommand.php index fd23ea2e..6eb6b7d6 100644 --- a/tools/ShowFieldsDescriptionCommand.php +++ b/tools/ShowFieldsDescriptionCommand.php @@ -5,6 +5,9 @@ namespace Bitrix24\SDK\Tools; use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\CoreBuilder; +use Bitrix24\SDK\Core\Credentials\Credentials; +use Bitrix24\SDK\Core\Credentials\WebhookUrl; use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Response\Response; use Psr\Log\LoggerInterface; @@ -80,9 +83,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int $io = new SymfonyStyle($input, $output); try { - $this->core = (new \Bitrix24\SDK\Core\CoreBuilder()) + $this->core = (new CoreBuilder()) ->withLogger($this->logger) - ->withWebhookUrl($b24Webhook) + ->withCredentials(Credentials::createFromWebhook(new WebhookUrl($b24Webhook))) ->build(); $methods = $this->core->call('methods', ['full' => true])->getResponseData()->getResult()->getResultData(); From 160727db0f05d9f2b819aff30e0dc15ae8a7e9da Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 3 Aug 2022 01:34:59 +0300 Subject: [PATCH 411/647] fix fabric for integration tests Signed-off-by: mesilov --- tests/Integration/Fabric.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/Integration/Fabric.php b/tests/Integration/Fabric.php index 7fcf7736..3d2357c9 100644 --- a/tests/Integration/Fabric.php +++ b/tests/Integration/Fabric.php @@ -10,6 +10,7 @@ use Bitrix24\SDK\Core\Contracts\CoreInterface; use Bitrix24\SDK\Core\CoreBuilder; use Bitrix24\SDK\Core\Credentials\Credentials; +use Bitrix24\SDK\Core\Credentials\WebhookUrl; use Bitrix24\SDK\Services\ServiceBuilder; use Monolog\Handler\StreamHandler; use Monolog\Logger; @@ -58,7 +59,11 @@ public static function getCore(): CoreInterface { return (new CoreBuilder()) ->withLogger(self::getLogger()) - ->withCredentials(Credentials::createFromWebhook($_ENV['BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK'] ?? $_ENV['BITRIX24_WEBHOOK'])) + ->withCredentials( + Credentials::createFromWebhook( + new WebhookUrl($_ENV['BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK'] ?? $_ENV['BITRIX24_WEBHOOK']) + ) + ) ->build(); } From 2f5b09430627c5ba7ada6a9a8e2b95d1ab80efca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Wed, 3 Aug 2022 11:57:58 +0300 Subject: [PATCH 412/647] -edit PersonTest.php -added a test to check the operation of products and transactions between themselves --- composer.json | 3 +- .../Services/MixedTest/MixedTest.php | 128 ++++++++++++++++++ tests/Unit/Services/TestPerson/PersonTest.php | 11 +- 3 files changed, 138 insertions(+), 4 deletions(-) create mode 100644 tests/Integration/Services/MixedTest/MixedTest.php diff --git a/composer.json b/composer.json index fdbf9b3b..f34ae8dc 100644 --- a/composer.json +++ b/composer.json @@ -42,7 +42,8 @@ "phpunit/phpunit": "9.5.*", "symfony/stopwatch": "5.4.* || 6.*", "roave/security-advisories": "dev-master", - "ext-intl": "*" + "ext-intl": "*", + "ext-http": "*" }, "autoload": { "psr-4": { diff --git a/tests/Integration/Services/MixedTest/MixedTest.php b/tests/Integration/Services/MixedTest/MixedTest.php new file mode 100644 index 00000000..3f0d3c1f --- /dev/null +++ b/tests/Integration/Services/MixedTest/MixedTest.php @@ -0,0 +1,128 @@ + array( + 'NAME' => '1С-Битрикс: Управление сайтом - Старт', + 'CURRENCY_ID' => 'RUB', + 'PRICE' => 4900, + 'SORT' => 4 + ) + ); + $queryDataForProduct1 = http_build_query($dataProduct1, 'https://b24-5p29et.bitrix24.ru/rest/1/113n4wi2ocu6rme0/crm.product.add') . PHP_EOL; + $resQueryForProduct1 = file_get_contents("https://b24-5p29et.bitrix24.ru/rest/1/113n4wi2ocu6rme0/crm.product.add?" . $queryDataForProduct1); + $decodeResQueryForProduct1 = json_decode($resQueryForProduct1, true, 512, JSON_THROW_ON_ERROR); + $idForProduct1 = $decodeResQueryForProduct1['result']; + $curl = curl_init(); + curl_setopt_array($curl, array( + CURLOPT_RETURNTRANSFER => 1, + CURLOPT_URL => $resQueryForProduct1, + )); + $response = curl_exec($curl); + curl_close($curl); + + //Создание продукта 2 + $dataProduct2 = array( + 'fields' => array( + 'NAME' => '1С-Битрикс: Управление сайтом - Старт 2 ', + 'CURRENCY_ID' => 'USD', + 'PRICE' => 4500, + 'SORT' => 1, + ) + ); + $queryDataForProduct2 = http_build_query($dataProduct2, 'https://b24-5p29et.bitrix24.ru/rest/1/113n4wi2ocu6rme0/crm.product.add') . PHP_EOL; + $resQueryForProduct2 = file_get_contents("https://b24-5p29et.bitrix24.ru/rest/1/113n4wi2ocu6rme0/crm.product.add?" . $queryDataForProduct2); + $decodeResQueryForProduct2 = json_decode($resQueryForProduct2, true, 512, JSON_THROW_ON_ERROR); + $idForProduct2 = $decodeResQueryForProduct2['result']; + $curl = curl_init(); + curl_setopt_array($curl, array( + CURLOPT_RETURNTRANSFER => 1, + CURLOPT_URL => $resQueryForProduct2, + )); + $response = curl_exec($curl); + curl_close($curl); + + //Создание Сделки + $dataDeal1 = array( + 'fields' => array( + 'TITLE' => 'test deal', + 'CURRENCY_ID' => 'USD', + 'OPPORTUNITY' => 500 + ) + ); + $queryDataForDeal1 = http_build_query($dataDeal1, 'https://b24-5p29et.bitrix24.ru/rest/1/113n4wi2ocu6rme0/crm.deal.add') . PHP_EOL; + $resQueryForDeal1 = file_get_contents("https://b24-5p29et.bitrix24.ru/rest/1/113n4wi2ocu6rme0/crm.deal.add?" . $queryDataForProduct1); + $decodeResQueryForDeal1 = json_decode($resQueryForDeal1, true, 512, JSON_THROW_ON_ERROR); + $idForDeal1 = $decodeResQueryForDeal1['result']; + $curl = curl_init(); + curl_setopt_array($curl, array( + CURLOPT_RETURNTRANSFER => 1, + CURLOPT_URL => $resQueryForDeal1, + )); + $response = curl_exec($curl); + curl_close($curl); + + //Добавление продукта в сделку + $addProductInDeal = array( + 'id' => $idForDeal1, + 'rows' => array( + [ + 'PRODUCT_ID' => $idForProduct1, + 'PRICE' => 100, + ], + [ + 'PRODUCT_ID' => $idForProduct2, + 'PRICE' => 100, + ] + ) + ); + $queryDataForProductInDeal = http_build_query($addProductInDeal, 'https://b24-5p29et.bitrix24.ru/rest/1/113n4wi2ocu6rme0/crm.deal.productrows.set') . PHP_EOL; + $resQueryForProductInDeal = file_get_contents("https://b24-5p29et.bitrix24.ru/rest/1/113n4wi2ocu6rme0/crm.deal.productrows.set?" . $queryDataForProductInDeal); + $decodeResQueryForDeal1 = json_decode($resQueryForProductInDeal, true, 512, JSON_THROW_ON_ERROR); + $curl = curl_init(); + curl_setopt_array($curl, array( + CURLOPT_RETURNTRANSFER => 1, + CURLOPT_URL => $resQueryForProductInDeal, + )); + $response = curl_exec($curl); + curl_close($curl); + + self::assertNotEmpty($dataProduct1); + self::assertNotEmpty($dataProduct2); + self::assertNotEmpty($dataDeal1); + self::assertNotEmpty($addProductInDeal); + } + + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public function setUp(): void + { + $this->productService = Fabric::getServiceBuilder()->getCRMScope()->product(); + $this->dealServices = Fabric::getServiceBuilder()->getCRMScope()->deal(); + } +} diff --git a/tests/Unit/Services/TestPerson/PersonTest.php b/tests/Unit/Services/TestPerson/PersonTest.php index 015ebe75..02154645 100644 --- a/tests/Unit/Services/TestPerson/PersonTest.php +++ b/tests/Unit/Services/TestPerson/PersonTest.php @@ -3,6 +3,8 @@ namespace Bitrix24\SDK\Tests\Unit\Services\TestPerson; +use Bitrix24\SDK\Services\CRM\Deal\Service\Deal; +use Bitrix24\SDK\Services\CRM\Product\Service\Product; use Money\Currency; use PHPUnit\Framework\TestCase; use Symfony\Component\Serializer\Encoder\JsonEncoder; @@ -18,6 +20,8 @@ class PersonTest extends TestCase { + protected Deal $deal; + protected Product $product; /** * @test */ @@ -74,7 +78,7 @@ public function NormalizeMoneyTest():void $serializer = new Serializer($normalizers, $encoders); - $dollars = new Money(100,new Currency('USD')); + $dollars = new Money(100, new Currency('USD')); $numberFormatter = new \NumberFormatter('en_US', \NumberFormatter::CURRENCY); $intlFormatter = new IntlMoneyFormatter($numberFormatter, new ISOCurrencies()); @@ -83,9 +87,10 @@ public function NormalizeMoneyTest():void 'USD' => $intlFormatter, ]); - $money = $moneyFormatter->format($dollars); - $jsonContent = $serializer->normalize($money,null, [AbstractNormalizer::ATTRIBUTES => ['amount']]); + $money = $moneyFormatter->format($dollars); + $jsonContent = $serializer->normalize($money, null, [AbstractNormalizer::ATTRIBUTES => ['amount']]); var_dump($jsonContent); self::assertNotEmpty($money); } + } \ No newline at end of file From 179a2ac7036a67752b91b5c71050c0751a873c58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Wed, 3 Aug 2022 16:59:37 +0300 Subject: [PATCH 413/647] -add custom Normalizer(not work) --- .../Services/TestPerson/PersonNormalizer.php | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 tests/Unit/Services/TestPerson/PersonNormalizer.php diff --git a/tests/Unit/Services/TestPerson/PersonNormalizer.php b/tests/Unit/Services/TestPerson/PersonNormalizer.php new file mode 100644 index 00000000..8368beb0 --- /dev/null +++ b/tests/Unit/Services/TestPerson/PersonNormalizer.php @@ -0,0 +1,39 @@ +router = $router; + $this->normalizer = $normalizer; + } + + public function normalize($person, string $format = null, array $context = []) + { + $data = $this->normalizer->normalize($person, $format, $context); + var_dump($data); + // Здесь, добавьте, измените или удалите некоторые данные: + return $this->router->generate('topic_show', [ + 'name' => $person->getName(), + ], UrlGeneratorInterface::ABSOLUTE_URL); + } + + public function supportsNormalization($data, string $format = null, array $context = []) + { + return $data instanceof Person; + } + +} \ No newline at end of file From a3e47c2ee0b588cf2289fb52ab942b61f5c95917 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 4 Aug 2022 01:16:48 +0300 Subject: [PATCH 414/647] delete Result.php Signed-off-by: mesilov --- CHANGELOG.md | 11 +++++----- docs/RU/Core/Auth/auth.md | 4 ++-- src/Core/Batch.php | 20 +++++++++---------- .../FilterWithoutBatchWithoutCountOrder.php | 6 +++--- src/Core/Response/DTO/Pagination.php | 10 ++-------- src/Core/Response/DTO/ResponseData.php | 10 +++++----- src/Core/Response/Response.php | 4 ++-- src/Core/Result/AddedItemBatchResult.php | 2 +- src/Core/Result/AddedItemResult.php | 2 +- src/Core/Result/DeletedItemBatchResult.php | 2 +- src/Core/Result/DeletedItemResult.php | 2 +- src/Core/Result/FieldsResult.php | 2 +- src/Core/Result/UpdatedItemBatchResult.php | 2 +- src/Core/Result/UpdatedItemResult.php | 2 +- .../CRM/Activity/Result/ActivitiesResult.php | 2 +- .../CRM/Activity/Result/ActivityResult.php | 2 +- .../CRM/Contact/Result/ContactResult.php | 2 +- .../Contact/Result/ContactUserfieldResult.php | 2 +- .../Result/ContactUserfieldsResult.php | 2 +- .../CRM/Contact/Result/ContactsResult.php | 2 +- .../CRM/Deal/Result/DealCategoriesResult.php | 2 +- .../CRM/Deal/Result/DealCategoryResult.php | 2 +- .../Deal/Result/DealCategoryStagesResult.php | 2 +- .../Deal/Result/DealCategoryStatusResult.php | 2 +- .../Deal/Result/DealContactItemsResult.php | 2 +- .../Deal/Result/DealProductRowItemsResult.php | 2 +- src/Services/CRM/Deal/Result/DealResult.php | 2 +- .../CRM/Deal/Result/DealUserfieldResult.php | 2 +- .../CRM/Deal/Result/DealUserfieldsResult.php | 2 +- src/Services/CRM/Deal/Result/DealsResult.php | 2 +- src/Services/CRM/Lead/Result/LeadResult.php | 2 +- src/Services/CRM/Lead/Result/LeadsResult.php | 2 +- .../CRM/Product/Result/ProductResult.php | 2 +- .../CRM/Product/Result/ProductsResult.php | 2 +- .../Settings/Result/SettingsModeResult.php | 2 +- .../Userfield/Result/UserfieldTypesResult.php | 2 +- .../Result/AddedMessageItemResult.php | 2 +- .../IMOpenLines/Result/JoinOpenLineResult.php | 2 +- .../Main/Result/ApplicationInfoResult.php | 2 +- .../Main/Result/EventHandlerBindResult.php | 2 +- .../Main/Result/EventHandlerUnbindResult.php | 2 +- .../Main/Result/EventHandlersResult.php | 2 +- src/Services/Main/Result/EventListResult.php | 2 +- .../Main/Result/IsUserAdminResult.php | 2 +- .../Main/Result/MethodAffordabilityResult.php | 4 ++-- src/Services/Main/Result/ServerTimeResult.php | 2 +- .../Main/Result/UserProfileResult.php | 2 +- .../Placement/Result/DeleteUserTypeResult.php | 2 +- .../Placement/Result/PlacementBindResult.php | 2 +- .../Result/PlacementLocationCodesResult.php | 2 +- .../Result/PlacementUnbindResult.php | 2 +- .../PlacementsLocationInformationResult.php | 2 +- .../Result/RegisterUserTypeResult.php | 2 +- .../Placement/Result/UserFieldTypesResult.php | 2 +- .../Result/CallAttachTranscriptionResult.php | 2 +- .../Result/ExternalCallFinishResult.php | 2 +- .../Result/ExternalCallHideResult.php | 2 +- .../Result/ExternalCallRecordResult.php | 2 +- .../Result/ExternalCallRegisterResult.php | 2 +- .../ExternalCallSearchCrmEntitiesResult.php | 2 +- .../Result/ExternalCallShowResult.php | 2 +- .../Result/ExternalLineAddResult.php | 2 +- .../Result/ExternalLineUpdateResult.php | 2 +- .../Telephony/Result/ExternalLinesResult.php | 2 +- .../Result/UserConsentAgreementResult.php | 2 +- .../Result/UserConsentAgreementTextResult.php | 2 +- .../Result/UserConsentAgreementsResult.php | 2 +- tests/Integration/Core/BatchTest.php | 8 ++++---- tests/Integration/Core/CoreTest.php | 2 +- .../IMOpenLines/Service/NetworkTest.php | 2 +- .../Services/Main/Service/MainTest.php | 8 ++++---- tools/ShowFieldsDescriptionCommand.php | 10 +++++----- 72 files changed, 106 insertions(+), 111 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 17f4e290..12e933af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # bitrix24-php-sdk change log -## 2.0-alpha.7 — 23.07.2022 +## 2.0-alpha.7 — 8.08.2022 ### Added @@ -45,11 +45,12 @@ * method `Services\Main\Service::getAvailableMethods` marks as deprecated * method `Services\Main\Service::getAllMethods` marks as deprecated * method `Services\Main\Service::getMethodsByScope` marks as deprecated -* fabric methods for `Bitrix24\SDK\Core\Credentials` - are [consistent](https://github.com/mesilov/bitrix24-php-sdk/issues/303): `createFromWebhook`, `createFromOAuth` +* ❗️fabric methods `Bitrix24\SDK\Core\Credentials` + renamed and now are [consistent](https://github.com/mesilov/bitrix24-php-sdk/issues/303): `createFromWebhook`, `createFromOAuth` , `createFromPlacementRequest` -* deleted [unused class](https://github.com/mesilov/bitrix24-php-sdk/issues/303) `Bitrix24\SDK\Core\Response\DTO\ResponseDataCollection` -* deleted [method](https://github.com/mesilov/bitrix24-php-sdk/issues/303) `CoreBuilder::withWebhookUrl`, use +* ❗️deleted [unused class](https://github.com/mesilov/bitrix24-php-sdk/issues/303) `Bitrix24\SDK\Core\Response\DTO\ResponseDataCollection` +* ❗️deleted [redundant class](https://github.com/mesilov/bitrix24-php-sdk/issues/303) `Bitrix24\SDK\Core\Response\DTO\Result` +* ❗️deleted [method](https://github.com/mesilov/bitrix24-php-sdk/issues/303) `CoreBuilder::withWebhookUrl`, use method `CoreBuilder::withCredentials` ### Bugfix diff --git a/docs/RU/Core/Auth/auth.md b/docs/RU/Core/Auth/auth.md index 2e0364f5..eaf66877 100644 --- a/docs/RU/Core/Auth/auth.md +++ b/docs/RU/Core/Auth/auth.md @@ -37,7 +37,7 @@ $result = json_decode($result->getContent(), true); var_dump($result); ``` -## подключение к Битрикс24 с использованием OAuth 2.0 +## подключение к Битрикс24 с использованием OAuth 2.0 ```php getResponseData()->getResult()->getResultData() as $cnt => $listElement) { + foreach ($firstResultPage->getResponseData()->getResult() as $cnt => $listElement) { $elementsCounter++; if ($limit !== null && $elementsCounter > $limit) { return; @@ -407,7 +407,7 @@ public function getTraversableList( // filtered elements count more than one result page(50 elements) // return first page $lastElementIdInFirstPage = null; - foreach ($firstResultPage->getResponseData()->getResult()->getResultData() as $cnt => $listElement) { + foreach ($firstResultPage->getResponseData()->getResult() as $cnt => $listElement) { $elementsCounter++; $lastElementIdInFirstPage = (int)$listElement['ID']; if ($limit !== null && $elementsCounter > $limit) { @@ -431,7 +431,7 @@ public function getTraversableList( 'start' => 0, ] ); - $lastElementId = (int)$lastResultPage->getResponseData()->getResult()->getResultData()[0]['ID']; + $lastElementId = (int)$lastResultPage->getResponseData()->getResult()[0]['ID']; // reverse order if you need if ($lastElementIdInFirstPage > $lastElementId) { $tmp = $lastElementIdInFirstPage; @@ -497,7 +497,7 @@ public function getTraversableList( ] ); // iterate items in batch query result - foreach ($queryResultData->getResult()->getResultData() as $cnt => $listElement) { + foreach ($queryResultData->getResult() as $cnt => $listElement) { $elementsCounter++; if ($limit !== null && $elementsCounter > $limit) { return; @@ -652,7 +652,7 @@ public function getTraversableListWithCount( ] ); // iterate items in batch query result - foreach ($queryResultData->getResult()->getResultData() as $cnt => $listElement) { + foreach ($queryResultData->getResult() as $cnt => $listElement) { $elementsCounter++; if ($limit !== null && $elementsCounter > $limit) { return; @@ -702,13 +702,13 @@ protected function getTraversable(bool $isHaltOnError): Generator // single queries // todo handle error field - $resultDataItems = $response->getResult()->getResultData()['result']; - $resultQueryTimeItems = $response->getResult()->getResultData()['result_time']; + $resultDataItems = $response->getResult()['result']; + $resultQueryTimeItems = $response->getResult()['result_time']; // list queries //todo handle result_error for list queries - $resultNextItems = $response->getResult()->getResultData()['result_next']; - $totalItems = $response->getResult()->getResultData()['result_total']; + $resultNextItems = $response->getResult()['result_next']; + $totalItems = $response->getResult()['result_total']; foreach ($resultDataItems as $singleQueryKey => $singleQueryResult) { if (!is_array($singleQueryResult)) { $singleQueryResult = [$singleQueryResult]; @@ -728,7 +728,7 @@ protected function getTraversable(bool $isHaltOnError): Generator } yield new ResponseData( - new Result($singleQueryResult), + $singleQueryResult, Time::initFromResponse($resultQueryTimeItems[$singleQueryKey]), new Pagination($nextItem, $total) ); diff --git a/src/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrder.php b/src/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrder.php index a2d1ce9e..e1d6c8c8 100644 --- a/src/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrder.php +++ b/src/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrder.php @@ -119,7 +119,7 @@ public function getTraversableList(string $apiMethod, array $order, array $filte ); - foreach ($resultPage->getResponseData()->getResult()->getResultData() as $cnt => $item) { + foreach ($resultPage->getResponseData()->getResult() as $cnt => $item) { $currentElementId = (int)$item['ID']; @@ -167,7 +167,7 @@ private function getFirstElementId(string $apiMethod, array $filter, array $sele ] ); - $elementId = $firstResultPage->getResponseData()->getResult()->getResultData()[0]['ID']; + $elementId = $firstResultPage->getResponseData()->getResult()[0]['ID']; $this->log->debug('FilterWithoutBatchWithoutCountOrder.getFirstElementId.finish', [ 'elementId' => $elementId, @@ -206,7 +206,7 @@ private function getLastElementId(string $apiMethod, array $filter, array $selec ] ); - $elementId = $lastResultPage->getResponseData()->getResult()->getResultData()[0]['ID']; + $elementId = $lastResultPage->getResponseData()->getResult()[0]['ID']; $this->log->debug('FilterWithoutBatchWithoutCountOrder.getLastElementId.finish', [ 'elementId' => $elementId, diff --git a/src/Core/Response/DTO/Pagination.php b/src/Core/Response/DTO/Pagination.php index eb0a5e4f..3f1816ef 100644 --- a/src/Core/Response/DTO/Pagination.php +++ b/src/Core/Response/DTO/Pagination.php @@ -11,14 +11,8 @@ */ class Pagination { - /** - * @var int|null - */ - private $nextItem; - /** - * @var int|null - */ - private $total; + private ?int $nextItem; + private ?int $total; /** * Pagination constructor. diff --git a/src/Core/Response/DTO/ResponseData.php b/src/Core/Response/DTO/ResponseData.php index 655925fe..f50484ff 100644 --- a/src/Core/Response/DTO/ResponseData.php +++ b/src/Core/Response/DTO/ResponseData.php @@ -11,18 +11,18 @@ */ class ResponseData { - protected Result $result; + protected array $result; protected Time $time; protected Pagination $pagination; /** * ResponseData constructor. * - * @param Result $result + * @param array $result * @param Time $time * @param Pagination $pagination */ - public function __construct(Result $result, Time $time, Pagination $pagination) + public function __construct(array $result, Time $time, Pagination $pagination) { $this->result = $result; $this->time = $time; @@ -46,9 +46,9 @@ public function getTime(): Time } /** - * @return Result + * @return array */ - public function getResult(): Result + public function getResult(): array { return $this->result; } diff --git a/src/Core/Response/Response.php b/src/Core/Response/Response.php index 81f53b58..75566327 100644 --- a/src/Core/Response/Response.php +++ b/src/Core/Response/Response.php @@ -21,9 +21,9 @@ class Response { protected ResponseInterface $httpResponse; - protected LoggerInterface $logger; protected ?DTO\ResponseData $responseData; protected Command $apiCommand; + protected LoggerInterface $logger; /** * Response constructor. @@ -109,7 +109,7 @@ public function getResponseData(): DTO\ResponseData } $this->responseData = new DTO\ResponseData( - new DTO\Result($responseResult['result']), + $responseResult['result'], DTO\Time::initFromResponse($responseResult['time']), new DTO\Pagination($nextItem, $total) ); diff --git a/src/Core/Result/AddedItemBatchResult.php b/src/Core/Result/AddedItemBatchResult.php index 793b8dca..14180bbe 100644 --- a/src/Core/Result/AddedItemBatchResult.php +++ b/src/Core/Result/AddedItemBatchResult.php @@ -29,6 +29,6 @@ public function getResponseData(): ResponseData public function getId(): int { - return (int)$this->getResponseData()->getResult()->getResultData()[0]; + return (int)$this->getResponseData()->getResult()[0]; } } \ No newline at end of file diff --git a/src/Core/Result/AddedItemResult.php b/src/Core/Result/AddedItemResult.php index fad8366d..bb491edc 100644 --- a/src/Core/Result/AddedItemResult.php +++ b/src/Core/Result/AddedItemResult.php @@ -20,6 +20,6 @@ class AddedItemResult extends AbstractResult implements AddedItemIdResultInterfa */ public function getId(): int { - return (int)$this->getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + return (int)$this->getCoreResponse()->getResponseData()->getResult()[0]; } } \ No newline at end of file diff --git a/src/Core/Result/DeletedItemBatchResult.php b/src/Core/Result/DeletedItemBatchResult.php index f8efe47b..d63e67ab 100644 --- a/src/Core/Result/DeletedItemBatchResult.php +++ b/src/Core/Result/DeletedItemBatchResult.php @@ -32,6 +32,6 @@ public function getResponseData(): ResponseData */ public function isSuccess(): bool { - return (bool)$this->getResponseData()->getResult()->getResultData()[0]; + return (bool)$this->getResponseData()->getResult()[0]; } } \ No newline at end of file diff --git a/src/Core/Result/DeletedItemResult.php b/src/Core/Result/DeletedItemResult.php index 3770582e..4eb5b4c4 100644 --- a/src/Core/Result/DeletedItemResult.php +++ b/src/Core/Result/DeletedItemResult.php @@ -20,6 +20,6 @@ class DeletedItemResult extends AbstractResult implements DeletedItemResultInter */ public function isSuccess(): bool { - return (bool)$this->getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; } } \ No newline at end of file diff --git a/src/Core/Result/FieldsResult.php b/src/Core/Result/FieldsResult.php index e997af4f..b9d7b435 100644 --- a/src/Core/Result/FieldsResult.php +++ b/src/Core/Result/FieldsResult.php @@ -19,6 +19,6 @@ class FieldsResult extends AbstractResult */ public function getFieldsDescription(): array { - return $this->getCoreResponse()->getResponseData()->getResult()->getResultData(); + return $this->getCoreResponse()->getResponseData()->getResult(); } } \ No newline at end of file diff --git a/src/Core/Result/UpdatedItemBatchResult.php b/src/Core/Result/UpdatedItemBatchResult.php index 6be791b7..e36de654 100644 --- a/src/Core/Result/UpdatedItemBatchResult.php +++ b/src/Core/Result/UpdatedItemBatchResult.php @@ -32,6 +32,6 @@ public function getResponseData(): ResponseData */ public function isSuccess(): bool { - return (bool)$this->getResponseData()->getResult()->getResultData()[0]; + return (bool)$this->getResponseData()->getResult()[0]; } } \ No newline at end of file diff --git a/src/Core/Result/UpdatedItemResult.php b/src/Core/Result/UpdatedItemResult.php index 7ee545e9..1995f034 100644 --- a/src/Core/Result/UpdatedItemResult.php +++ b/src/Core/Result/UpdatedItemResult.php @@ -19,6 +19,6 @@ class UpdatedItemResult extends AbstractResult */ public function isSuccess(): bool { - return (bool)$this->getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; } } \ No newline at end of file diff --git a/src/Services/CRM/Activity/Result/ActivitiesResult.php b/src/Services/CRM/Activity/Result/ActivitiesResult.php index 1eef454a..ce52ce3d 100644 --- a/src/Services/CRM/Activity/Result/ActivitiesResult.php +++ b/src/Services/CRM/Activity/Result/ActivitiesResult.php @@ -17,7 +17,7 @@ class ActivitiesResult extends AbstractResult public function getActivities(): array { $res = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { $res[] = new ActivityItemResult($item); } diff --git a/src/Services/CRM/Activity/Result/ActivityResult.php b/src/Services/CRM/Activity/Result/ActivityResult.php index 08f1590d..4b17e7ef 100644 --- a/src/Services/CRM/Activity/Result/ActivityResult.php +++ b/src/Services/CRM/Activity/Result/ActivityResult.php @@ -11,6 +11,6 @@ class ActivityResult extends AbstractResult { public function activity(): ActivityItemResult { - return new ActivityItemResult($this->getCoreResponse()->getResponseData()->getResult()->getResultData()); + return new ActivityItemResult($this->getCoreResponse()->getResponseData()->getResult()); } } \ No newline at end of file diff --git a/src/Services/CRM/Contact/Result/ContactResult.php b/src/Services/CRM/Contact/Result/ContactResult.php index 4d58a917..4999cbdc 100644 --- a/src/Services/CRM/Contact/Result/ContactResult.php +++ b/src/Services/CRM/Contact/Result/ContactResult.php @@ -16,6 +16,6 @@ class ContactResult extends AbstractResult { public function contact(): ContactItemResult { - return new ContactItemResult($this->getCoreResponse()->getResponseData()->getResult()->getResultData()); + return new ContactItemResult($this->getCoreResponse()->getResponseData()->getResult()); } } \ No newline at end of file diff --git a/src/Services/CRM/Contact/Result/ContactUserfieldResult.php b/src/Services/CRM/Contact/Result/ContactUserfieldResult.php index 253b4b34..d1b50369 100644 --- a/src/Services/CRM/Contact/Result/ContactUserfieldResult.php +++ b/src/Services/CRM/Contact/Result/ContactUserfieldResult.php @@ -13,6 +13,6 @@ class ContactUserfieldResult extends AbstractResult */ public function userfieldItem(): ContactUserfieldItemResult { - return new ContactUserfieldItemResult($this->getCoreResponse()->getResponseData()->getResult()->getResultData()); + return new ContactUserfieldItemResult($this->getCoreResponse()->getResponseData()->getResult()); } } \ No newline at end of file diff --git a/src/Services/CRM/Contact/Result/ContactUserfieldsResult.php b/src/Services/CRM/Contact/Result/ContactUserfieldsResult.php index fc583cb4..30dbc44f 100644 --- a/src/Services/CRM/Contact/Result/ContactUserfieldsResult.php +++ b/src/Services/CRM/Contact/Result/ContactUserfieldsResult.php @@ -16,7 +16,7 @@ class ContactUserfieldsResult extends AbstractResult public function getUserfields(): array { $res = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { $res[] = new ContactUserfieldItemResult($item); } diff --git a/src/Services/CRM/Contact/Result/ContactsResult.php b/src/Services/CRM/Contact/Result/ContactsResult.php index 2e8748f2..82a0b2a4 100644 --- a/src/Services/CRM/Contact/Result/ContactsResult.php +++ b/src/Services/CRM/Contact/Result/ContactsResult.php @@ -22,7 +22,7 @@ class ContactsResult extends AbstractResult public function getContacts(): array { $res = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { $res[] = new ContactItemResult($item); } diff --git a/src/Services/CRM/Deal/Result/DealCategoriesResult.php b/src/Services/CRM/Deal/Result/DealCategoriesResult.php index f8d8eee5..9d90c2bc 100644 --- a/src/Services/CRM/Deal/Result/DealCategoriesResult.php +++ b/src/Services/CRM/Deal/Result/DealCategoriesResult.php @@ -22,7 +22,7 @@ class DealCategoriesResult extends AbstractResult public function getDealCategories(): array { $res = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $dealCategory) { + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $dealCategory) { $res[] = new DealCategoryItemResult($dealCategory); } diff --git a/src/Services/CRM/Deal/Result/DealCategoryResult.php b/src/Services/CRM/Deal/Result/DealCategoryResult.php index e146c865..53d6867e 100644 --- a/src/Services/CRM/Deal/Result/DealCategoryResult.php +++ b/src/Services/CRM/Deal/Result/DealCategoryResult.php @@ -16,6 +16,6 @@ class DealCategoryResult extends AbstractResult { public function getDealCategoryFields(): DealCategoryItemResult { - return new DealCategoryItemResult($this->getCoreResponse()->getResponseData()->getResult()->getResultData()); + return new DealCategoryItemResult($this->getCoreResponse()->getResponseData()->getResult()); } } \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealCategoryStagesResult.php b/src/Services/CRM/Deal/Result/DealCategoryStagesResult.php index 9e2a51ea..c4f9ce82 100644 --- a/src/Services/CRM/Deal/Result/DealCategoryStagesResult.php +++ b/src/Services/CRM/Deal/Result/DealCategoryStagesResult.php @@ -23,7 +23,7 @@ class DealCategoryStagesResult extends AbstractResult public function getDealCategoryStages(): array { $res = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $deal) { + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $deal) { $res[] = new DealCategoryStageItemResult($deal); } diff --git a/src/Services/CRM/Deal/Result/DealCategoryStatusResult.php b/src/Services/CRM/Deal/Result/DealCategoryStatusResult.php index 68ea8e06..4236ec4b 100644 --- a/src/Services/CRM/Deal/Result/DealCategoryStatusResult.php +++ b/src/Services/CRM/Deal/Result/DealCategoryStatusResult.php @@ -21,6 +21,6 @@ class DealCategoryStatusResult extends AbstractResult */ public function getDealCategoryTypeId(): string { - return $this->getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + return $this->getCoreResponse()->getResponseData()->getResult()[0]; } } \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealContactItemsResult.php b/src/Services/CRM/Deal/Result/DealContactItemsResult.php index b0f639d8..6f8a40c1 100644 --- a/src/Services/CRM/Deal/Result/DealContactItemsResult.php +++ b/src/Services/CRM/Deal/Result/DealContactItemsResult.php @@ -21,7 +21,7 @@ class DealContactItemsResult extends AbstractResult public function getDealContacts(): array { $res = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $dealContact) { + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $dealContact) { $res[] = new DealContactItemResult($dealContact); } diff --git a/src/Services/CRM/Deal/Result/DealProductRowItemsResult.php b/src/Services/CRM/Deal/Result/DealProductRowItemsResult.php index 7104799b..06e78113 100644 --- a/src/Services/CRM/Deal/Result/DealProductRowItemsResult.php +++ b/src/Services/CRM/Deal/Result/DealProductRowItemsResult.php @@ -22,7 +22,7 @@ class DealProductRowItemsResult extends AbstractResult public function getProductRows(): array { $res = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $productRow) { + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $productRow) { $res[] = new DealProductRowItemResult($productRow); } diff --git a/src/Services/CRM/Deal/Result/DealResult.php b/src/Services/CRM/Deal/Result/DealResult.php index 91687e3a..4e9e01c3 100644 --- a/src/Services/CRM/Deal/Result/DealResult.php +++ b/src/Services/CRM/Deal/Result/DealResult.php @@ -16,6 +16,6 @@ class DealResult extends AbstractResult { public function deal(): DealItemResult { - return new DealItemResult($this->getCoreResponse()->getResponseData()->getResult()->getResultData()); + return new DealItemResult($this->getCoreResponse()->getResponseData()->getResult()); } } \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealUserfieldResult.php b/src/Services/CRM/Deal/Result/DealUserfieldResult.php index 60380774..4358c882 100644 --- a/src/Services/CRM/Deal/Result/DealUserfieldResult.php +++ b/src/Services/CRM/Deal/Result/DealUserfieldResult.php @@ -14,6 +14,6 @@ class DealUserfieldResult extends AbstractResult */ public function userfieldItem(): DealUserfieldItemResult { - return new DealUserfieldItemResult($this->getCoreResponse()->getResponseData()->getResult()->getResultData()); + return new DealUserfieldItemResult($this->getCoreResponse()->getResponseData()->getResult()); } } \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealUserfieldsResult.php b/src/Services/CRM/Deal/Result/DealUserfieldsResult.php index af523d1a..2aa60219 100644 --- a/src/Services/CRM/Deal/Result/DealUserfieldsResult.php +++ b/src/Services/CRM/Deal/Result/DealUserfieldsResult.php @@ -17,7 +17,7 @@ class DealUserfieldsResult extends AbstractResult public function getUserfields(): array { $res = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { $res[] = new DealUserfieldItemResult($item); } diff --git a/src/Services/CRM/Deal/Result/DealsResult.php b/src/Services/CRM/Deal/Result/DealsResult.php index 2481a7dd..3fdaa070 100644 --- a/src/Services/CRM/Deal/Result/DealsResult.php +++ b/src/Services/CRM/Deal/Result/DealsResult.php @@ -22,7 +22,7 @@ class DealsResult extends AbstractResult public function getDeals(): array { $res = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $deal) { + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $deal) { $res[] = new DealItemResult($deal); } diff --git a/src/Services/CRM/Lead/Result/LeadResult.php b/src/Services/CRM/Lead/Result/LeadResult.php index 7e476650..5fbfcc91 100644 --- a/src/Services/CRM/Lead/Result/LeadResult.php +++ b/src/Services/CRM/Lead/Result/LeadResult.php @@ -19,6 +19,6 @@ class LeadResult extends AbstractResult */ public function lead(): LeadItemResult { - return new LeadItemResult($this->getCoreResponse()->getResponseData()->getResult()->getResultData()); + return new LeadItemResult($this->getCoreResponse()->getResponseData()->getResult()); } } \ No newline at end of file diff --git a/src/Services/CRM/Lead/Result/LeadsResult.php b/src/Services/CRM/Lead/Result/LeadsResult.php index 77131b48..2a2ebef3 100644 --- a/src/Services/CRM/Lead/Result/LeadsResult.php +++ b/src/Services/CRM/Lead/Result/LeadsResult.php @@ -22,7 +22,7 @@ class LeadsResult extends AbstractResult public function getLeads(): array { $items = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { $items[] = new LeadItemResult($item); } diff --git a/src/Services/CRM/Product/Result/ProductResult.php b/src/Services/CRM/Product/Result/ProductResult.php index 0feea5f6..07ba6828 100644 --- a/src/Services/CRM/Product/Result/ProductResult.php +++ b/src/Services/CRM/Product/Result/ProductResult.php @@ -11,6 +11,6 @@ class ProductResult extends AbstractResult { public function product(): ProductItemResult { - return new ProductItemResult($this->getCoreResponse()->getResponseData()->getResult()->getResultData()); + return new ProductItemResult($this->getCoreResponse()->getResponseData()->getResult()); } } \ No newline at end of file diff --git a/src/Services/CRM/Product/Result/ProductsResult.php b/src/Services/CRM/Product/Result/ProductsResult.php index a3814d85..dd8caf80 100644 --- a/src/Services/CRM/Product/Result/ProductsResult.php +++ b/src/Services/CRM/Product/Result/ProductsResult.php @@ -22,7 +22,7 @@ class ProductsResult extends AbstractResult public function getProducts(): array { $res = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { $res[] = new ProductItemResult($item); } diff --git a/src/Services/CRM/Settings/Result/SettingsModeResult.php b/src/Services/CRM/Settings/Result/SettingsModeResult.php index 63996e6d..25167743 100644 --- a/src/Services/CRM/Settings/Result/SettingsModeResult.php +++ b/src/Services/CRM/Settings/Result/SettingsModeResult.php @@ -15,6 +15,6 @@ class SettingsModeResult extends AbstractResult { public function getModeId(): int { - return $this->getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + return $this->getCoreResponse()->getResponseData()->getResult()[0]; } } \ No newline at end of file diff --git a/src/Services/CRM/Userfield/Result/UserfieldTypesResult.php b/src/Services/CRM/Userfield/Result/UserfieldTypesResult.php index 212f2a58..507caa83 100644 --- a/src/Services/CRM/Userfield/Result/UserfieldTypesResult.php +++ b/src/Services/CRM/Userfield/Result/UserfieldTypesResult.php @@ -16,7 +16,7 @@ class UserfieldTypesResult extends AbstractResult public function getTypes(): array { $res = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { $res[] = new UserfieldTypeItemResult($item); } diff --git a/src/Services/IMOpenLines/Result/AddedMessageItemResult.php b/src/Services/IMOpenLines/Result/AddedMessageItemResult.php index b381263e..c9683cc1 100644 --- a/src/Services/IMOpenLines/Result/AddedMessageItemResult.php +++ b/src/Services/IMOpenLines/Result/AddedMessageItemResult.php @@ -16,6 +16,6 @@ class AddedMessageItemResult extends AbstractResult */ public function isSuccess(): bool { - return (bool)$this->getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; } } \ No newline at end of file diff --git a/src/Services/IMOpenLines/Result/JoinOpenLineResult.php b/src/Services/IMOpenLines/Result/JoinOpenLineResult.php index 2254051b..516824ef 100644 --- a/src/Services/IMOpenLines/Result/JoinOpenLineResult.php +++ b/src/Services/IMOpenLines/Result/JoinOpenLineResult.php @@ -15,6 +15,6 @@ class JoinOpenLineResult extends AbstractResult implements AddedItemIdResultInte */ public function getId(): int { - return (int)$this->getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + return (int)$this->getCoreResponse()->getResponseData()->getResult()[0]; } } \ No newline at end of file diff --git a/src/Services/Main/Result/ApplicationInfoResult.php b/src/Services/Main/Result/ApplicationInfoResult.php index db41cf23..b6c61fca 100644 --- a/src/Services/Main/Result/ApplicationInfoResult.php +++ b/src/Services/Main/Result/ApplicationInfoResult.php @@ -11,6 +11,6 @@ class ApplicationInfoResult extends AbstractResult { public function applicationInfo(): ApplicationInfoItemResult { - return new ApplicationInfoItemResult($this->getCoreResponse()->getResponseData()->getResult()->getResultData()); + return new ApplicationInfoItemResult($this->getCoreResponse()->getResponseData()->getResult()); } } \ No newline at end of file diff --git a/src/Services/Main/Result/EventHandlerBindResult.php b/src/Services/Main/Result/EventHandlerBindResult.php index 44ef622d..bf511882 100644 --- a/src/Services/Main/Result/EventHandlerBindResult.php +++ b/src/Services/Main/Result/EventHandlerBindResult.php @@ -15,6 +15,6 @@ class EventHandlerBindResult extends AbstractResult */ public function isBinded(): bool { - return (bool)$this->getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; } } \ No newline at end of file diff --git a/src/Services/Main/Result/EventHandlerUnbindResult.php b/src/Services/Main/Result/EventHandlerUnbindResult.php index 8a95ad0f..47aa9136 100644 --- a/src/Services/Main/Result/EventHandlerUnbindResult.php +++ b/src/Services/Main/Result/EventHandlerUnbindResult.php @@ -15,6 +15,6 @@ class EventHandlerUnbindResult extends AbstractResult */ public function getUnbindedHandlersCount(): int { - return (int)$this->getCoreResponse()->getResponseData()->getResult()->getResultData()['count']; + return (int)$this->getCoreResponse()->getResponseData()->getResult()['count']; } } \ No newline at end of file diff --git a/src/Services/Main/Result/EventHandlersResult.php b/src/Services/Main/Result/EventHandlersResult.php index 990aab49..7addf375 100644 --- a/src/Services/Main/Result/EventHandlersResult.php +++ b/src/Services/Main/Result/EventHandlersResult.php @@ -16,7 +16,7 @@ class EventHandlersResult extends AbstractResult public function getEventHandlers(): array { $res = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $event) { + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $event) { $res[] = new EventHandlerItemResult($event); } diff --git a/src/Services/Main/Result/EventListResult.php b/src/Services/Main/Result/EventListResult.php index 36bc8b78..695cf217 100644 --- a/src/Services/Main/Result/EventListResult.php +++ b/src/Services/Main/Result/EventListResult.php @@ -15,6 +15,6 @@ class EventListResult extends AbstractResult */ public function getEvents(): array { - return $this->getCoreResponse()->getResponseData()->getResult()->getResultData(); + return $this->getCoreResponse()->getResponseData()->getResult(); } } \ No newline at end of file diff --git a/src/Services/Main/Result/IsUserAdminResult.php b/src/Services/Main/Result/IsUserAdminResult.php index 434993f8..1bee191b 100644 --- a/src/Services/Main/Result/IsUserAdminResult.php +++ b/src/Services/Main/Result/IsUserAdminResult.php @@ -15,6 +15,6 @@ class IsUserAdminResult extends AbstractResult */ public function isAdmin(): bool { - return (bool)$this->getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; } } \ No newline at end of file diff --git a/src/Services/Main/Result/MethodAffordabilityResult.php b/src/Services/Main/Result/MethodAffordabilityResult.php index d15a5fbc..ad64373c 100644 --- a/src/Services/Main/Result/MethodAffordabilityResult.php +++ b/src/Services/Main/Result/MethodAffordabilityResult.php @@ -15,7 +15,7 @@ class MethodAffordabilityResult extends AbstractResult */ public function isExisting(): bool { - return $this->getCoreResponse()->getResponseData()->getResult()->getResultData()['isExisting']; + return $this->getCoreResponse()->getResponseData()->getResult()['isExisting']; } /** @@ -24,6 +24,6 @@ public function isExisting(): bool */ public function isAvailable(): bool { - return $this->getCoreResponse()->getResponseData()->getResult()->getResultData()['isAvailable']; + return $this->getCoreResponse()->getResponseData()->getResult()['isAvailable']; } } \ No newline at end of file diff --git a/src/Services/Main/Result/ServerTimeResult.php b/src/Services/Main/Result/ServerTimeResult.php index 04d340fa..45d11321 100644 --- a/src/Services/Main/Result/ServerTimeResult.php +++ b/src/Services/Main/Result/ServerTimeResult.php @@ -16,6 +16,6 @@ class ServerTimeResult extends AbstractResult */ public function time(): DateTimeImmutable { - return new DateTimeImmutable($this->getCoreResponse()->getResponseData()->getResult()->getResultData()[0]); + return new DateTimeImmutable($this->getCoreResponse()->getResponseData()->getResult()[0]); } } \ No newline at end of file diff --git a/src/Services/Main/Result/UserProfileResult.php b/src/Services/Main/Result/UserProfileResult.php index a17810a4..2885e435 100644 --- a/src/Services/Main/Result/UserProfileResult.php +++ b/src/Services/Main/Result/UserProfileResult.php @@ -11,6 +11,6 @@ class UserProfileResult extends AbstractResult { public function getUserProfile(): UserProfileItemResult { - return new UserProfileItemResult($this->getCoreResponse()->getResponseData()->getResult()->getResultData()); + return new UserProfileItemResult($this->getCoreResponse()->getResponseData()->getResult()); } } \ No newline at end of file diff --git a/src/Services/Placement/Result/DeleteUserTypeResult.php b/src/Services/Placement/Result/DeleteUserTypeResult.php index 4b785316..66cfb1ce 100644 --- a/src/Services/Placement/Result/DeleteUserTypeResult.php +++ b/src/Services/Placement/Result/DeleteUserTypeResult.php @@ -15,6 +15,6 @@ class DeleteUserTypeResult extends AbstractResult */ public function isSuccess(): bool { - return (bool)$this->getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; } } \ No newline at end of file diff --git a/src/Services/Placement/Result/PlacementBindResult.php b/src/Services/Placement/Result/PlacementBindResult.php index 39d98fa5..4dfa0ddd 100644 --- a/src/Services/Placement/Result/PlacementBindResult.php +++ b/src/Services/Placement/Result/PlacementBindResult.php @@ -15,6 +15,6 @@ class PlacementBindResult extends AbstractResult */ public function isSuccess(): bool { - return (bool)$this->getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; } } \ No newline at end of file diff --git a/src/Services/Placement/Result/PlacementLocationCodesResult.php b/src/Services/Placement/Result/PlacementLocationCodesResult.php index f1876fd0..0804042b 100644 --- a/src/Services/Placement/Result/PlacementLocationCodesResult.php +++ b/src/Services/Placement/Result/PlacementLocationCodesResult.php @@ -14,6 +14,6 @@ class PlacementLocationCodesResult extends AbstractResult */ public function getLocationCodes(): array { - return $this->getCoreResponse()->getResponseData()->getResult()->getResultData(); + return $this->getCoreResponse()->getResponseData()->getResult(); } } \ No newline at end of file diff --git a/src/Services/Placement/Result/PlacementUnbindResult.php b/src/Services/Placement/Result/PlacementUnbindResult.php index 73cccf8e..51dd7e51 100644 --- a/src/Services/Placement/Result/PlacementUnbindResult.php +++ b/src/Services/Placement/Result/PlacementUnbindResult.php @@ -15,6 +15,6 @@ class PlacementUnbindResult extends AbstractResult */ public function getDeletedPlacementHandlersCount(): int { - return (int)$this->getCoreResponse()->getResponseData()->getResult()->getResultData()['count']; + return (int)$this->getCoreResponse()->getResponseData()->getResult()['count']; } } \ No newline at end of file diff --git a/src/Services/Placement/Result/PlacementsLocationInformationResult.php b/src/Services/Placement/Result/PlacementsLocationInformationResult.php index e24590a4..328f3ae4 100644 --- a/src/Services/Placement/Result/PlacementsLocationInformationResult.php +++ b/src/Services/Placement/Result/PlacementsLocationInformationResult.php @@ -16,7 +16,7 @@ class PlacementsLocationInformationResult extends AbstractResult public function getPlacementsLocationInformation(): array { $res = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { $res[] = new PlacementLocationItemResult($item); } diff --git a/src/Services/Placement/Result/RegisterUserTypeResult.php b/src/Services/Placement/Result/RegisterUserTypeResult.php index dee044e8..2a0c6baf 100644 --- a/src/Services/Placement/Result/RegisterUserTypeResult.php +++ b/src/Services/Placement/Result/RegisterUserTypeResult.php @@ -15,6 +15,6 @@ class RegisterUserTypeResult extends AbstractResult */ public function isSuccess(): bool { - return (bool)$this->getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; } } \ No newline at end of file diff --git a/src/Services/Placement/Result/UserFieldTypesResult.php b/src/Services/Placement/Result/UserFieldTypesResult.php index a59753e1..5496a458 100644 --- a/src/Services/Placement/Result/UserFieldTypesResult.php +++ b/src/Services/Placement/Result/UserFieldTypesResult.php @@ -15,7 +15,7 @@ class UserFieldTypesResult extends AbstractResult public function getUserFieldTypes(): array { $res = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { $res[] = new UserFieldTypeItemResult($item); } diff --git a/src/Services/Telephony/Result/CallAttachTranscriptionResult.php b/src/Services/Telephony/Result/CallAttachTranscriptionResult.php index 089049cc..d68269ca 100644 --- a/src/Services/Telephony/Result/CallAttachTranscriptionResult.php +++ b/src/Services/Telephony/Result/CallAttachTranscriptionResult.php @@ -25,6 +25,6 @@ class CallAttachTranscriptionResult extends AbstractResult implements AddedItemI public function getId():int { - return $this->getCoreResponse()->getResponseData()->getResult()->getResultData()['TRANSCRIPT_ID']; + return $this->getCoreResponse()->getResponseData()->getResult()['TRANSCRIPT_ID']; } } \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalCallFinishResult.php b/src/Services/Telephony/Result/ExternalCallFinishResult.php index d552dd6e..f7622c71 100644 --- a/src/Services/Telephony/Result/ExternalCallFinishResult.php +++ b/src/Services/Telephony/Result/ExternalCallFinishResult.php @@ -24,6 +24,6 @@ class ExternalCallFinishResult extends AbstractResult */ public function getExternalCallFinish(): ExternalCallFinishItemResult { - return new ExternalCallFinishItemResult($this->getCoreResponse()->getResponseData()->getResult()->getResultData()); + 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 index 5f9df65b..b1a0661f 100644 --- a/src/Services/Telephony/Result/ExternalCallHideResult.php +++ b/src/Services/Telephony/Result/ExternalCallHideResult.php @@ -26,6 +26,6 @@ class ExternalCallHideResult extends AbstractResult public function isHided(): bool { - return $this->getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + 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 index 3e7aeafb..7437a324 100644 --- a/src/Services/Telephony/Result/ExternalCallRecordResult.php +++ b/src/Services/Telephony/Result/ExternalCallRecordResult.php @@ -23,6 +23,6 @@ class ExternalCallRecordResult extends AbstractResult */ public function getFileId():int { - return $this->getCoreResponse()->getResponseData()->getResult()->getResultData()['FILE_ID']; + return $this->getCoreResponse()->getResponseData()->getResult()['FILE_ID']; } } \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalCallRegisterResult.php b/src/Services/Telephony/Result/ExternalCallRegisterResult.php index 7610d80d..232cca7e 100644 --- a/src/Services/Telephony/Result/ExternalCallRegisterResult.php +++ b/src/Services/Telephony/Result/ExternalCallRegisterResult.php @@ -24,7 +24,7 @@ class ExternalCallRegisterResult extends AbstractResult */ public function getExternalCallRegister(): ExternalCallRegisterItemResult { - return new ExternalCallRegisterItemResult($this->getCoreResponse()->getResponseData()->getResult()->getResultData()); + return new ExternalCallRegisterItemResult($this->getCoreResponse()->getResponseData()->getResult()); } } \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesResult.php b/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesResult.php index d74d19c7..7d67626c 100644 --- a/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesResult.php +++ b/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesResult.php @@ -25,7 +25,7 @@ class ExternalCallSearchCrmEntitiesResult extends AbstractResult public function getCrmEntitiesSearchResult():array { $res = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { $res[] = new ExternalCallSearchCrmEntitiesItemResult($item); } diff --git a/src/Services/Telephony/Result/ExternalCallShowResult.php b/src/Services/Telephony/Result/ExternalCallShowResult.php index 2b73f185..d275e402 100644 --- a/src/Services/Telephony/Result/ExternalCallShowResult.php +++ b/src/Services/Telephony/Result/ExternalCallShowResult.php @@ -27,7 +27,7 @@ class ExternalCallShowResult extends AbstractResult public function isShown(): bool { - return $this->getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + return $this->getCoreResponse()->getResponseData()->getResult()[0]; } diff --git a/src/Services/Telephony/Result/ExternalLineAddResult.php b/src/Services/Telephony/Result/ExternalLineAddResult.php index 1b1f6f54..c287a5f9 100644 --- a/src/Services/Telephony/Result/ExternalLineAddResult.php +++ b/src/Services/Telephony/Result/ExternalLineAddResult.php @@ -25,7 +25,7 @@ class ExternalLineAddResult extends AbstractResult implements AddedItemIdResultI */ public function getId(): int { - return $this->getCoreResponse()->getResponseData()->getResult()->getResultData()['ID']; + return $this->getCoreResponse()->getResponseData()->getResult()['ID']; } } \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalLineUpdateResult.php b/src/Services/Telephony/Result/ExternalLineUpdateResult.php index 6eed88f8..3e08575d 100644 --- a/src/Services/Telephony/Result/ExternalLineUpdateResult.php +++ b/src/Services/Telephony/Result/ExternalLineUpdateResult.php @@ -24,6 +24,6 @@ class ExternalLineUpdateResult extends AbstractResult */ public function updateExternalLineId():int { - return (int)$this->getCoreResponse()->getResponseData()->getResult()->getResultData()['ID']; + 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 index eee79926..9345c9eb 100644 --- a/src/Services/Telephony/Result/ExternalLinesResult.php +++ b/src/Services/Telephony/Result/ExternalLinesResult.php @@ -24,7 +24,7 @@ class ExternalLinesResult extends AbstractResult public function getExternalLines(): array { $res = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { $res[] = new ExternalLineItemResult($item); } diff --git a/src/Services/UserConsent/Result/UserConsentAgreementResult.php b/src/Services/UserConsent/Result/UserConsentAgreementResult.php index a361300c..9738998c 100644 --- a/src/Services/UserConsent/Result/UserConsentAgreementResult.php +++ b/src/Services/UserConsent/Result/UserConsentAgreementResult.php @@ -15,6 +15,6 @@ class UserConsentAgreementResult extends AbstractResult */ public function agreement(): UserConsentAgreementItemResult { - return new UserConsentAgreementItemResult($this->getCoreResponse()->getResponseData()->getResult()->getResultData()); + return new UserConsentAgreementItemResult($this->getCoreResponse()->getResponseData()->getResult()); } } \ No newline at end of file diff --git a/src/Services/UserConsent/Result/UserConsentAgreementTextResult.php b/src/Services/UserConsent/Result/UserConsentAgreementTextResult.php index 72f9033f..591c16d5 100644 --- a/src/Services/UserConsent/Result/UserConsentAgreementTextResult.php +++ b/src/Services/UserConsent/Result/UserConsentAgreementTextResult.php @@ -15,6 +15,6 @@ class UserConsentAgreementTextResult extends AbstractResult */ public function text(): UserConsentAgreementTextItemResult { - return new UserConsentAgreementTextItemResult($this->getCoreResponse()->getResponseData()->getResult()->getResultData()); + return new UserConsentAgreementTextItemResult($this->getCoreResponse()->getResponseData()->getResult()); } } \ No newline at end of file diff --git a/src/Services/UserConsent/Result/UserConsentAgreementsResult.php b/src/Services/UserConsent/Result/UserConsentAgreementsResult.php index 2267cbad..0992ef0d 100644 --- a/src/Services/UserConsent/Result/UserConsentAgreementsResult.php +++ b/src/Services/UserConsent/Result/UserConsentAgreementsResult.php @@ -17,7 +17,7 @@ class UserConsentAgreementsResult extends AbstractResult public function getAgreements(): array { $res = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { $res[] = new UserConsentAgreementItemResult($item); } diff --git a/tests/Integration/Core/BatchTest.php b/tests/Integration/Core/BatchTest.php index 6221f217..1aaf427e 100644 --- a/tests/Integration/Core/BatchTest.php +++ b/tests/Integration/Core/BatchTest.php @@ -296,7 +296,7 @@ public function testBatchAddEntityItems(): void // add deals to bitrix24 $dealIdList = []; foreach ($this->batch->addEntityItems('crm.deal.add', $rawDeals) as $cnt => $addDealResult) { - $dealIdList[] = $addDealResult->getResult()->getResultData()[0]; + $dealIdList[] = $addDealResult->getResult()[0]; } $this->assertCount(self::DEMO_DATA_ARRAY_SIZE_LESS_THAN_PAGE, $dealIdList); } @@ -335,14 +335,14 @@ public function testBatchDeleteEntityItems(): void // add deals to bitrix24 $dealIdList = []; foreach ($this->batch->addEntityItems('crm.deal.add', $rawDeals) as $cnt => $addDealResult) { - $dealIdList[] = $addDealResult->getResult()->getResultData()[0]; + $dealIdList[] = $addDealResult->getResult()[0]; } $this->assertCount(self::DEMO_DATA_ARRAY_SIZE_LESS_THAN_PAGE, $dealIdList); // delete deals from bitrix24 $dealsDeleteResult = []; foreach ($this->batch->deleteEntityItems('crm.deal.delete', $dealIdList) as $cnt => $deleteDealResult) { - $dealsDeleteResult[] = $deleteDealResult->getResult()->getResultData()[0]; + $dealsDeleteResult[] = $deleteDealResult->getResult()[0]; } $this->assertCount(self::DEMO_DATA_ARRAY_SIZE_LESS_THAN_PAGE, $dealsDeleteResult); } @@ -356,7 +356,7 @@ public function testBatchDeleteEntityItemsWithWrongTypeOfEntityId(): void { $this->expectException(InvalidArgumentException::class); foreach ($this->batch->deleteEntityItems('crm.deal.delete', [1, 2, '3', 4, 5]) as $cnt => $deleteDealResult) { - $dealsDeleteResult[] = $deleteDealResult->getResult()->getResultData()[0]; + $dealsDeleteResult[] = $deleteDealResult->getResult()[0]; } } diff --git a/tests/Integration/Core/CoreTest.php b/tests/Integration/Core/CoreTest.php index 0d8d9132..5b590193 100644 --- a/tests/Integration/Core/CoreTest.php +++ b/tests/Integration/Core/CoreTest.php @@ -25,7 +25,7 @@ class CoreTest extends TestCase public function testCallExistingApiMethod(): void { $response = $this->core->call('app.info'); - $this->assertIsArray($response->getResponseData()->getResult()->getResultData()); + $this->assertIsArray($response->getResponseData()->getResult()); } /** diff --git a/tests/Integration/Services/IMOpenLines/Service/NetworkTest.php b/tests/Integration/Services/IMOpenLines/Service/NetworkTest.php index 50c9a76e..80948a9e 100644 --- a/tests/Integration/Services/IMOpenLines/Service/NetworkTest.php +++ b/tests/Integration/Services/IMOpenLines/Service/NetworkTest.php @@ -36,7 +36,7 @@ public function testMessageAdd(): void { $res = $this->networkService->messageAdd( Fabric::getOpenLineCode(), - (int)$this->networkService->core->call('PROFILE')->getResponseData()->getResult()->getResultData()['ID'], + (int)$this->networkService->core->call('PROFILE')->getResponseData()->getResult()['ID'], sprintf('Test message at %s', time()) ); diff --git a/tests/Integration/Services/Main/Service/MainTest.php b/tests/Integration/Services/Main/Service/MainTest.php index afc052b8..d4bd3adc 100644 --- a/tests/Integration/Services/Main/Service/MainTest.php +++ b/tests/Integration/Services/Main/Service/MainTest.php @@ -79,7 +79,7 @@ public function testApplicationInfo(): void */ public function testGetAvailableScope(): void { - $scope = new Scope($this->mainService->getAvailableScope()->getResponseData()->getResult()->getResultData()); + $scope = new Scope($this->mainService->getAvailableScope()->getResponseData()->getResult()); $this->assertIsArray($scope->getScopeCodes()); } @@ -92,8 +92,8 @@ public function testGetAvailableScope(): void public function testGetCurrentScope(): void { $this->assertGreaterThanOrEqual( - count((new Scope($this->mainService->getCurrentScope()->getResponseData()->getResult()->getResultData()))->getScopeCodes()), - count((new Scope($this->mainService->getAvailableScope()->getResponseData()->getResult()->getResultData()))->getScopeCodes()) + count((new Scope($this->mainService->getCurrentScope()->getResponseData()->getResult()))->getScopeCodes()), + count((new Scope($this->mainService->getAvailableScope()->getResponseData()->getResult()))->getScopeCodes()) ); } @@ -106,7 +106,7 @@ public function testGetCurrentScope(): void */ public function testGetAvailableMethods(): void { - $this->assertIsArray($this->mainService->getAvailableMethods()->getResponseData()->getResult()->getResultData()); + $this->assertIsArray($this->mainService->getAvailableMethods()->getResponseData()->getResult()); } public function setUp(): void diff --git a/tools/ShowFieldsDescriptionCommand.php b/tools/ShowFieldsDescriptionCommand.php index 6eb6b7d6..af6254c9 100644 --- a/tools/ShowFieldsDescriptionCommand.php +++ b/tools/ShowFieldsDescriptionCommand.php @@ -88,7 +88,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int ->withCredentials(Credentials::createFromWebhook(new WebhookUrl($b24Webhook))) ->build(); - $methods = $this->core->call('methods', ['full' => true])->getResponseData()->getResult()->getResultData(); + $methods = $this->core->call('methods', ['full' => true])->getResponseData()->getResult(); $fieldsMethods = []; foreach ($methods as $method) { if (strpos($method, 'fields') !== false) { @@ -167,7 +167,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int private function showFieldsAsPhpDocFunctionSelectSuggest(OutputInterface $output, Response $fields): void { $fieldsList = []; - foreach ($fields->getResponseData()->getResult()->getResultData() as $fieldCode => $fieldDescription) { + foreach ($fields->getResponseData()->getResult() as $fieldCode => $fieldDescription) { $fieldsList[] = sprintf("'%s'", $fieldCode); } $output->writeln(' * @param array $select = [' . implode(',', $fieldsList) . ']'); @@ -182,7 +182,7 @@ private function showFieldsAsPhpDocFunctionSelectSuggest(OutputInterface $output private function showFieldsAsPhpDocFunctionProperty(OutputInterface $output, Response $fields): void { $fieldsList = ['*', '* @param array{']; - foreach ($fields->getResponseData()->getResult()->getResultData() as $fieldCode => $fieldDescription) { + foreach ($fields->getResponseData()->getResult() as $fieldCode => $fieldDescription) { switch (strtolower($fieldDescription['type'])) { case 'integer': $phpDocType = 'int'; @@ -209,7 +209,7 @@ private function showFieldsAsPhpDocFunctionProperty(OutputInterface $output, Res private function showFieldsAsPhpDocClassHeader(OutputInterface $output, Response $fields): void { $fieldsList = ['/**', '*']; - foreach ($fields->getResponseData()->getResult()->getResultData() as $fieldCode => $fieldDescription) { + foreach ($fields->getResponseData()->getResult() as $fieldCode => $fieldDescription) { switch (strtolower($fieldDescription['type'])) { case 'integer': $phpDocType = 'int'; @@ -236,7 +236,7 @@ private function showFieldsAsTable(OutputInterface $output, Response $fields): v { $fieldsTable = []; // some methods return description in upper case - $fields = array_change_key_case($fields->getResponseData()->getResult()->getResultData(), CASE_LOWER); + $fields = array_change_key_case($fields->getResponseData()->getResult(), CASE_LOWER); foreach ($fields as $fieldCode => $fieldDescription) { $fieldDescription = array_change_key_case($fieldDescription, CASE_LOWER); From 7844c8766d8cdd995384f577327c2840e83dad63 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 4 Aug 2022 01:17:56 +0300 Subject: [PATCH 415/647] delete Result.php from codebase Signed-off-by: mesilov --- src/Core/Response/DTO/Result.php | 33 -------------------------------- 1 file changed, 33 deletions(-) delete mode 100644 src/Core/Response/DTO/Result.php diff --git a/src/Core/Response/DTO/Result.php b/src/Core/Response/DTO/Result.php deleted file mode 100644 index b5ddf9cc..00000000 --- a/src/Core/Response/DTO/Result.php +++ /dev/null @@ -1,33 +0,0 @@ -result = $result; - } - - /** - * @return array - */ - public function getResultData(): array - { - return $this->result; - } -} \ No newline at end of file From cce3d06747b34855ca18cd0e445260240cd4a32d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Thu, 4 Aug 2022 14:30:25 +0300 Subject: [PATCH 416/647] -edit MixedTest.php - the test works with the help of services --- composer.json | 3 +- .../Services/MixedTest/MixedTest.php | 115 ++++++------------ 2 files changed, 40 insertions(+), 78 deletions(-) diff --git a/composer.json b/composer.json index f34ae8dc..fdbf9b3b 100644 --- a/composer.json +++ b/composer.json @@ -42,8 +42,7 @@ "phpunit/phpunit": "9.5.*", "symfony/stopwatch": "5.4.* || 6.*", "roave/security-advisories": "dev-master", - "ext-intl": "*", - "ext-http": "*" + "ext-intl": "*" }, "autoload": { "psr-4": { diff --git a/tests/Integration/Services/MixedTest/MixedTest.php b/tests/Integration/Services/MixedTest/MixedTest.php index 3f0d3c1f..fb7bff7b 100644 --- a/tests/Integration/Services/MixedTest/MixedTest.php +++ b/tests/Integration/Services/MixedTest/MixedTest.php @@ -5,115 +5,77 @@ namespace Bitrix24\SDK\Tests\Integration\Services\MixedTest; use Bitrix24\SDK\Services\CRM\Deal\Service\Deal; +use Bitrix24\SDK\Services\CRM\Deal\Service\DealProductRows; use Bitrix24\SDK\Services\CRM\Product\Service\Product; use Monolog\Test\TestCase; use Bitrix24\SDK\Tests\Integration\Fabric; +use Bitrix24\SDK\Core\Exceptions\TransportException; use http; use Bitrix24\SDK\Core\Exceptions\BaseException; -use Bitrix24\SDK\Core\Exceptions\TransportException; + class MixedTest extends TestCase { protected Deal $dealServices; protected Product $productService; + protected DealProductRows $dealProductRows; /** * @test - * @throws \JsonException + * @throws BaseException + * @throws TransportException */ public function DealWithProductsTest(): void { //Создание продукта 1 $dataProduct1 = array( - 'fields' => array( - 'NAME' => '1С-Битрикс: Управление сайтом - Старт', + + 'NAME' => 'wine', 'CURRENCY_ID' => 'RUB', - 'PRICE' => 4900, - 'SORT' => 4 - ) + 'PRICE' => 475, + 'SORT' => 1 + ); - $queryDataForProduct1 = http_build_query($dataProduct1, 'https://b24-5p29et.bitrix24.ru/rest/1/113n4wi2ocu6rme0/crm.product.add') . PHP_EOL; - $resQueryForProduct1 = file_get_contents("https://b24-5p29et.bitrix24.ru/rest/1/113n4wi2ocu6rme0/crm.product.add?" . $queryDataForProduct1); - $decodeResQueryForProduct1 = json_decode($resQueryForProduct1, true, 512, JSON_THROW_ON_ERROR); - $idForProduct1 = $decodeResQueryForProduct1['result']; - $curl = curl_init(); - curl_setopt_array($curl, array( - CURLOPT_RETURNTRANSFER => 1, - CURLOPT_URL => $resQueryForProduct1, - )); - $response = curl_exec($curl); - curl_close($curl); + $productId1 = $this->productService->add($dataProduct1)->getId(); //Создание продукта 2 $dataProduct2 = array( - 'fields' => array( - 'NAME' => '1С-Битрикс: Управление сайтом - Старт 2 ', - 'CURRENCY_ID' => 'USD', - 'PRICE' => 4500, - 'SORT' => 1, - ) + + 'NAME' => 'vodka', + 'CURRENCY_ID' => 'RUB', + 'PRICE' => 675, + 'SORT' => 4 + ); - $queryDataForProduct2 = http_build_query($dataProduct2, 'https://b24-5p29et.bitrix24.ru/rest/1/113n4wi2ocu6rme0/crm.product.add') . PHP_EOL; - $resQueryForProduct2 = file_get_contents("https://b24-5p29et.bitrix24.ru/rest/1/113n4wi2ocu6rme0/crm.product.add?" . $queryDataForProduct2); - $decodeResQueryForProduct2 = json_decode($resQueryForProduct2, true, 512, JSON_THROW_ON_ERROR); - $idForProduct2 = $decodeResQueryForProduct2['result']; - $curl = curl_init(); - curl_setopt_array($curl, array( - CURLOPT_RETURNTRANSFER => 1, - CURLOPT_URL => $resQueryForProduct2, - )); - $response = curl_exec($curl); - curl_close($curl); + $productId2 = $this->productService->add($dataProduct2)->getId(); + //Создание Сделки $dataDeal1 = array( - 'fields' => array( - 'TITLE' => 'test deal', - 'CURRENCY_ID' => 'USD', - 'OPPORTUNITY' => 500 - ) + 'TITLE' => 'sale of alcohol', + 'CURRENCY_ID' => 'RUB', ); - $queryDataForDeal1 = http_build_query($dataDeal1, 'https://b24-5p29et.bitrix24.ru/rest/1/113n4wi2ocu6rme0/crm.deal.add') . PHP_EOL; - $resQueryForDeal1 = file_get_contents("https://b24-5p29et.bitrix24.ru/rest/1/113n4wi2ocu6rme0/crm.deal.add?" . $queryDataForProduct1); - $decodeResQueryForDeal1 = json_decode($resQueryForDeal1, true, 512, JSON_THROW_ON_ERROR); - $idForDeal1 = $decodeResQueryForDeal1['result']; - $curl = curl_init(); - curl_setopt_array($curl, array( - CURLOPT_RETURNTRANSFER => 1, - CURLOPT_URL => $resQueryForDeal1, - )); - $response = curl_exec($curl); - curl_close($curl); - - //Добавление продукта в сделку - $addProductInDeal = array( - 'id' => $idForDeal1, - 'rows' => array( + $dealId1 = $this->dealServices->add($dataDeal1)->getId(); + + $productsForDeal = array( + [ - 'PRODUCT_ID' => $idForProduct1, - 'PRICE' => 100, + 'PRODUCT_ID' => $productId1, + 'PRICE' => 400, + 'QUANTITY' => 1 ], [ - 'PRODUCT_ID' => $idForProduct2, - 'PRICE' => 100, + 'PRODUCT_ID' => $productId2, + 'PRICE' => 500, + 'QUANTITY' => 1 ] - ) + ); - $queryDataForProductInDeal = http_build_query($addProductInDeal, 'https://b24-5p29et.bitrix24.ru/rest/1/113n4wi2ocu6rme0/crm.deal.productrows.set') . PHP_EOL; - $resQueryForProductInDeal = file_get_contents("https://b24-5p29et.bitrix24.ru/rest/1/113n4wi2ocu6rme0/crm.deal.productrows.set?" . $queryDataForProductInDeal); - $decodeResQueryForDeal1 = json_decode($resQueryForProductInDeal, true, 512, JSON_THROW_ON_ERROR); - $curl = curl_init(); - curl_setopt_array($curl, array( - CURLOPT_RETURNTRANSFER => 1, - CURLOPT_URL => $resQueryForProductInDeal, - )); - $response = curl_exec($curl); - curl_close($curl); - - self::assertNotEmpty($dataProduct1); - self::assertNotEmpty($dataProduct2); - self::assertNotEmpty($dataDeal1); - self::assertNotEmpty($addProductInDeal); + + $addProductInDeal = $this->dealProductRows->set($dealId1, $productsForDeal); + + + self::assertGreaterThanOrEqual(1, $productId1); } @@ -124,5 +86,6 @@ public function setUp(): void { $this->productService = Fabric::getServiceBuilder()->getCRMScope()->product(); $this->dealServices = Fabric::getServiceBuilder()->getCRMScope()->deal(); + $this->dealProductRows = Fabric::getServiceBuilder()->getCRMScope()->dealProductRows(); } } From 4feb8b4f14553585f4802dbce518bb6e50f6754c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Thu, 4 Aug 2022 17:15:26 +0300 Subject: [PATCH 417/647] -update test --- .../Integration/Services/MixedTest/MixedTest.php | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/tests/Integration/Services/MixedTest/MixedTest.php b/tests/Integration/Services/MixedTest/MixedTest.php index fb7bff7b..b84c223a 100644 --- a/tests/Integration/Services/MixedTest/MixedTest.php +++ b/tests/Integration/Services/MixedTest/MixedTest.php @@ -10,7 +10,6 @@ use Monolog\Test\TestCase; use Bitrix24\SDK\Tests\Integration\Fabric; use Bitrix24\SDK\Core\Exceptions\TransportException; -use http; use Bitrix24\SDK\Core\Exceptions\BaseException; @@ -31,8 +30,8 @@ public function DealWithProductsTest(): void $dataProduct1 = array( 'NAME' => 'wine', - 'CURRENCY_ID' => 'RUB', - 'PRICE' => 475, + 'CURRENCY_ID' => 'USD', + 'PRICE' => 100, 'SORT' => 1 ); @@ -42,8 +41,8 @@ public function DealWithProductsTest(): void $dataProduct2 = array( 'NAME' => 'vodka', - 'CURRENCY_ID' => 'RUB', - 'PRICE' => 675, + 'CURRENCY_ID' => 'USD', + 'PRICE' => 10, 'SORT' => 4 ); @@ -61,7 +60,7 @@ public function DealWithProductsTest(): void [ 'PRODUCT_ID' => $productId1, - 'PRICE' => 400, + 'PRICE' => 5000, 'QUANTITY' => 1 ], [ @@ -75,7 +74,11 @@ public function DealWithProductsTest(): void $addProductInDeal = $this->dealProductRows->set($dealId1, $productsForDeal); + self::assertEquals($productsForDeal[0]['PRICE'],$this->dealProductRows->get($dealId1)->getCoreResponse()->getResponseData()->getResult()->getResultData()[0]['PRICE']); + self::assertEquals($productsForDeal[1]['PRICE'],$this->dealProductRows->get($dealId1)->getCoreResponse()->getResponseData()->getResult()->getResultData()[1]['PRICE']); self::assertGreaterThanOrEqual(1, $productId1); + self::assertGreaterThanOrEqual(1, $productId2); + self::assertTrue((bool)$addProductInDeal); } From ea30810b1678b96eee72c3a6f717655fcf2bdd18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Sat, 6 Aug 2022 09:00:16 +0300 Subject: [PATCH 418/647] -edit normalizer(but I don't understand how to use it) --- .../Services/TestPerson/PersonNormalizer.php | 29 ++++++++++--------- tests/Unit/Services/TestPerson/PersonTest.php | 21 ++++++++++++++ 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/tests/Unit/Services/TestPerson/PersonNormalizer.php b/tests/Unit/Services/TestPerson/PersonNormalizer.php index 8368beb0..c8b386dc 100644 --- a/tests/Unit/Services/TestPerson/PersonNormalizer.php +++ b/tests/Unit/Services/TestPerson/PersonNormalizer.php @@ -5,35 +5,36 @@ namespace Bitrix24\SDK\Tests\Unit\Services\TestPerson; use Bitrix24\SDK\Tests\Unit\Services\TestPerson\Person; -use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Serializer\Normalizer\ContextAwareNormalizerInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; -class PersonNormalizer implements ContextAwareNormalizerInterface +class PersonNormalizer implements NormalizerInterface, ContextAwareNormalizerInterface { - private UrlGeneratorInterface $router; private ObjectNormalizer $normalizer; - protected Person $person; - public function __construct(UrlGeneratorInterface $router, ObjectNormalizer $normalizer) + public function __construct( ObjectNormalizer $normalizer) { - $this->router = $router; $this->normalizer = $normalizer; } - public function normalize($person, string $format = null, array $context = []) + /** + * @param Person $object + * @throws \Symfony\Component\Serializer\Exception\ExceptionInterface + */ + public function normalize($object, string $format = null, array $context = []):array { - $data = $this->normalizer->normalize($person, $format, $context); - var_dump($data); - // Здесь, добавьте, измените или удалите некоторые данные: - return $this->router->generate('topic_show', [ - 'name' => $person->getName(), - ], UrlGeneratorInterface::ABSOLUTE_URL); + $data = $this->normalizer->normalize($object,$format,$context); + return [ + 'name' => 'new_name', + 'lastname' => 'new_lastname', + ]; } - public function supportsNormalization($data, string $format = null, array $context = []) + public function supportsNormalization($data, string $format = null, array $context = []):bool { return $data instanceof Person; } + } \ No newline at end of file diff --git a/tests/Unit/Services/TestPerson/PersonTest.php b/tests/Unit/Services/TestPerson/PersonTest.php index 02154645..5d0b354f 100644 --- a/tests/Unit/Services/TestPerson/PersonTest.php +++ b/tests/Unit/Services/TestPerson/PersonTest.php @@ -16,6 +16,7 @@ use Money\Formatter\AggregateMoneyFormatter; use Money\Formatter\IntlMoneyFormatter; use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; +use Bitrix24\SDK\Tests\Unit\Services\TestPerson\PersonNormalizer; class PersonTest extends TestCase @@ -67,6 +68,26 @@ public function DeserializeTest():void{ self::assertNotEmpty($person); } + /** + *@test + */ + public function NormalizePersonTest():void + { + $person = new Person(); + $encoders = [new XmlEncoder(), new JsonEncoder()]; + $normalizers = [new PersonNormalizer()]; + + $serializer = new Serializer($normalizers, $encoders); + + $person->setName('Kirill'); + $person->setLastName('Khramov'); + + $jsonContent = $serializer->serialize($person, 'json'); + self::assertNotEmpty($jsonContent); + echo $jsonContent; + + } + /** * @test * @throws \Symfony\Component\Serializer\Exception\ExceptionInterface From 568a508c4beda210adf0ec1824c5e54a327ec4b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Wed, 10 Aug 2022 18:24:47 +0300 Subject: [PATCH 419/647] -add money result in AbstactCrmItem (not work) --- .../CRM/Common/Result/AbstractCrmItem.php | 5 ++-- .../Deal/Result/DealProductRowItemResult.php | 26 +++++++++++-------- .../Deal/Result/DealProductRowItemsResult.php | 10 +++++++ .../CRM/Deal/Service/DealProductRows.php | 4 ++- .../CRM/Deal/Service/DealProductRowsTest.php | 8 ++++++ 5 files changed, 39 insertions(+), 14 deletions(-) diff --git a/src/Services/CRM/Common/Result/AbstractCrmItem.php b/src/Services/CRM/Common/Result/AbstractCrmItem.php index 0737315f..71d7b341 100644 --- a/src/Services/CRM/Common/Result/AbstractCrmItem.php +++ b/src/Services/CRM/Common/Result/AbstractCrmItem.php @@ -7,6 +7,7 @@ use Bitrix24\SDK\Core\Result\AbstractItem; use Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNotFoundException; use DateTimeImmutable; +use Money\Money; class AbstractCrmItem extends AbstractItem { @@ -30,6 +31,8 @@ public function __get($offset) case 'LEAD_ID': case 'CONTACT_ID': case 'QUOTE_ID': + // productRow + case 'OWNER_ID': if ($this->data[$offset] !== '' && $this->data[$offset] !== null) { return (int)$this->data[$offset]; } @@ -39,9 +42,7 @@ public function __get($offset) if ($this->data[$offset] !== '' && $this->data[$offset] !== null && $this->data[$offset] !== '0') { return (int)$this->data[$offset]; } - return null; - // contact case 'EXPORT': case 'HAS_PHONE': diff --git a/src/Services/CRM/Deal/Result/DealProductRowItemResult.php b/src/Services/CRM/Deal/Result/DealProductRowItemResult.php index 5632778b..e0ddb29a 100644 --- a/src/Services/CRM/Deal/Result/DealProductRowItemResult.php +++ b/src/Services/CRM/Deal/Result/DealProductRowItemResult.php @@ -5,30 +5,34 @@ namespace Bitrix24\SDK\Services\CRM\Deal\Result; use Bitrix24\SDK\Core\Result\AbstractItem; +use Bitrix24\SDK\Services\CRM\Common\Result\AbstractCrmItem; +use Money\Money; /** * Class DealProductRowItemResult * - * @property-read int $ID - * @property-read int $OWNER_ID + * @property-read int $ID + * @property-read int $OWNER_ID * @property-read string $OWNER_TYPE - * @property-read int $PRODUCT_ID + * @property-read int $PRODUCT_ID * @property-read string $PRODUCT_NAME - * @property-read string $PRICE - * @property-read string $PRICE_EXCLUSIVE - * @property-read string $PRICE_NETTO - * @property-read string $PRICE_BRUTTO + * @property-read Money $PRICE + * @property-read Money $PRICE_EXCLUSIVE + * @property-read Money $PRICE_NETTO + * @property-read Money $PRICE_BRUTTO * @property-read string $QUANTITY - * @property-read int $DISCOUNT_TYPE_ID + * @property-read int $DISCOUNT_TYPE_ID * @property-read string $DISCOUNT_RATE * @property-read string $DISCOUNT_SUM * @property-read string $TAX_RATE * @property-read string $TAX_INCLUDED * @property-read string $CUSTOMIZED - * @property-read int $MEASURE_CODE + * @property-read int $MEASURE_CODE * @property-read string $MEASURE_NAME - * @property-read int $SORT + * @property-read int $RESERVE_ID + * @property-read int $RESERVE_QUANTITY + * @property-read int $SORT */ -class DealProductRowItemResult extends AbstractItem +class DealProductRowItemResult extends AbstractCrmItem { } \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealProductRowItemsResult.php b/src/Services/CRM/Deal/Result/DealProductRowItemsResult.php index 7104799b..125295a5 100644 --- a/src/Services/CRM/Deal/Result/DealProductRowItemsResult.php +++ b/src/Services/CRM/Deal/Result/DealProductRowItemsResult.php @@ -6,7 +6,9 @@ namespace Bitrix24\SDK\Services\CRM\Deal\Result; use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Response\Response; use Bitrix24\SDK\Core\Result\AbstractResult; +use Money\Currency; /** * Class DealProductRowItemsResult @@ -15,6 +17,14 @@ */ class DealProductRowItemsResult extends AbstractResult { + private Currency $currency; + + public function __construct(Response $coreResponse,Currency $currency) + { + parent::__construct($coreResponse); + $this->currency = $currency; + } + /** * @return DealProductRowItemResult[] * @throws BaseException diff --git a/src/Services/CRM/Deal/Service/DealProductRows.php b/src/Services/CRM/Deal/Service/DealProductRows.php index 3704bd20..c3867819 100644 --- a/src/Services/CRM/Deal/Service/DealProductRows.php +++ b/src/Services/CRM/Deal/Service/DealProductRows.php @@ -9,6 +9,7 @@ use Bitrix24\SDK\Core\Result\UpdatedItemResult; use Bitrix24\SDK\Services\AbstractService; use Bitrix24\SDK\Services\CRM\Deal\Result\DealProductRowItemsResult; +use Money\Currency; /** * Class DealProductRows @@ -36,7 +37,8 @@ public function get(int $dealId): DealProductRowItemsResult [ 'id' => $dealId, ] - ) + ), + new Currency('RUB') ); } diff --git a/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php b/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php index 0b45ad41..f9afb1c7 100644 --- a/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php +++ b/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php @@ -9,6 +9,7 @@ use Bitrix24\SDK\Services\CRM\Deal\Service\Deal; use Bitrix24\SDK\Services\CRM\Deal\Service\DealProductRows; use Bitrix24\SDK\Tests\Integration\Fabric; +use Money\Money; use PHPUnit\Framework\TestCase; /** @@ -28,6 +29,7 @@ class DealProductRowsTest extends TestCase */ public function testSet(): void { + $newDealId = $this->dealService->add(['TITLE' => 'test deal'])->getId(); $this::assertCount(0, $this->dealProductRowsService->get($newDealId)->getProductRows()); $this::assertTrue( @@ -41,6 +43,12 @@ public function testSet(): void )->isSuccess() ); $this::assertCount(1, $this->dealProductRowsService->get($newDealId)->getProductRows()); + $mas = $this->dealProductRowsService->get($newDealId)->getProductRows()[0]; + var_dump($mas); + var_dump($mas->ID); + var_dump($mas->OWNER_ID); + var_dump($mas->QUANTITY); + var_dump($mas->PRICE); } /** From 385de8e9e0a0a4c90a35279703e65c35a4c94630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Sat, 13 Aug 2022 09:21:54 +0300 Subject: [PATCH 420/647] -add money result in AbstactCrmItem (work?) -edit test --- composer.json | 6 +++--- src/Services/CRM/Common/Result/AbstractCrmItem.php | 6 ++++++ .../CRM/Deal/Service/DealProductRowsTest.php | 14 ++++++++++---- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/composer.json b/composer.json index fdbf9b3b..7485fa08 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,8 @@ "moneyphp/money": "3.* || 4.*", "symfony/serializer": "6.*||^6.1", "symfony/routing": "^4.4|^5.3|^6.0", - "symfony/property-access": "6.* || 6.1.*" + "symfony/property-access": "6.* || 6.1.*", + "ext-intl": "*" }, "require-dev": { "monolog/monolog": "2.1.*", @@ -41,8 +42,7 @@ "phpstan/phpstan": "1.*", "phpunit/phpunit": "9.5.*", "symfony/stopwatch": "5.4.* || 6.*", - "roave/security-advisories": "dev-master", - "ext-intl": "*" + "roave/security-advisories": "dev-master" }, "autoload": { "psr-4": { diff --git a/src/Services/CRM/Common/Result/AbstractCrmItem.php b/src/Services/CRM/Common/Result/AbstractCrmItem.php index 71d7b341..6be40bfd 100644 --- a/src/Services/CRM/Common/Result/AbstractCrmItem.php +++ b/src/Services/CRM/Common/Result/AbstractCrmItem.php @@ -7,6 +7,7 @@ use Bitrix24\SDK\Core\Result\AbstractItem; use Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNotFoundException; use DateTimeImmutable; +use Money\Currency; use Money\Money; class AbstractCrmItem extends AbstractItem @@ -50,6 +51,11 @@ public function __get($offset) case 'HAS_IMOL': case 'OPENED': // deal + case 'PRICE': + if ($this->data[$offset] !== '' && $this->data[$offset] !== null) { + return new Money($this->data[$offset],new Currency('RUB')); + } + return null; case 'IS_MANUAL_OPPORTUNITY': case 'CLOSED': case 'IS_NEW': diff --git a/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php b/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php index f9afb1c7..bba2891b 100644 --- a/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php +++ b/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php @@ -9,6 +9,9 @@ use Bitrix24\SDK\Services\CRM\Deal\Service\Deal; use Bitrix24\SDK\Services\CRM\Deal\Service\DealProductRows; use Bitrix24\SDK\Tests\Integration\Fabric; +use Money\Currencies\ISOCurrencies; +use Money\Currency; +use Money\Formatter\DecimalMoneyFormatter; use Money\Money; use PHPUnit\Framework\TestCase; @@ -30,6 +33,10 @@ class DealProductRowsTest extends TestCase public function testSet(): void { + $callCosts = new Money(1000, new Currency('RUB')); + $currencies = new ISOCurrencies(); + + $moneyFormatter = new DecimalMoneyFormatter($currencies); $newDealId = $this->dealService->add(['TITLE' => 'test deal'])->getId(); $this::assertCount(0, $this->dealProductRowsService->get($newDealId)->getProductRows()); $this::assertTrue( @@ -38,6 +45,7 @@ public function testSet(): void [ [ 'PRODUCT_NAME' => 'qqqq', + 'PRICE'=> $moneyFormatter->format($callCosts), ], ] )->isSuccess() @@ -45,10 +53,8 @@ public function testSet(): void $this::assertCount(1, $this->dealProductRowsService->get($newDealId)->getProductRows()); $mas = $this->dealProductRowsService->get($newDealId)->getProductRows()[0]; var_dump($mas); - var_dump($mas->ID); - var_dump($mas->OWNER_ID); - var_dump($mas->QUANTITY); - var_dump($mas->PRICE); + $price = $mas->PRICE; + var_dump($price); } /** From 67b0b486f4fb2be6ea9f4680e2e9672bcfb97a03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Wed, 17 Aug 2022 15:04:42 +0300 Subject: [PATCH 421/647] -edit money result in AbstactCrmItem (work?) -edit test --- src/Services/CRM/Common/Result/AbstractCrmItem.php | 4 +++- .../Services/CRM/Deal/Service/DealProductRowsTest.php | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Services/CRM/Common/Result/AbstractCrmItem.php b/src/Services/CRM/Common/Result/AbstractCrmItem.php index 6be40bfd..d2997b5a 100644 --- a/src/Services/CRM/Common/Result/AbstractCrmItem.php +++ b/src/Services/CRM/Common/Result/AbstractCrmItem.php @@ -52,8 +52,10 @@ public function __get($offset) case 'OPENED': // deal case 'PRICE': + if ($this->data[$offset] !== '' && $this->data[$offset] !== null) { - return new Money($this->data[$offset],new Currency('RUB')); + $var = $this->data[$offset] * 100; + return new Money((string)$var,new Currency('RUB')); } return null; case 'IS_MANUAL_OPPORTUNITY': diff --git a/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php b/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php index bba2891b..35696eca 100644 --- a/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php +++ b/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php @@ -33,7 +33,7 @@ class DealProductRowsTest extends TestCase public function testSet(): void { - $callCosts = new Money(1000, new Currency('RUB')); + $callCosts = new Money(1050, new Currency('RUB')); $currencies = new ISOCurrencies(); $moneyFormatter = new DecimalMoneyFormatter($currencies); @@ -52,9 +52,9 @@ public function testSet(): void ); $this::assertCount(1, $this->dealProductRowsService->get($newDealId)->getProductRows()); $mas = $this->dealProductRowsService->get($newDealId)->getProductRows()[0]; - var_dump($mas); - $price = $mas->PRICE; - var_dump($price); + $money = $moneyFormatter->format($mas->PRICE); + + } /** From ea8484193af3c9b165af6b4a80792b7e7c208a38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Fri, 19 Aug 2022 18:50:06 +0300 Subject: [PATCH 422/647] -edit test -add improvements to the method DEAL_PRODUCT_ROW so that it can use the currency --- .../CRM/Common/Result/AbstractCrmItem.php | 6 ++- .../Deal/Result/DealProductRowItemResult.php | 26 ++++++++++++- .../Deal/Result/DealProductRowItemsResult.php | 2 +- .../CRM/Deal/Service/DealProductRows.php | 39 ++++++++++++++++++- .../CRM/Deal/Service/DealProductRowsTest.php | 13 +++++-- 5 files changed, 78 insertions(+), 8 deletions(-) diff --git a/src/Services/CRM/Common/Result/AbstractCrmItem.php b/src/Services/CRM/Common/Result/AbstractCrmItem.php index d2997b5a..16a8c501 100644 --- a/src/Services/CRM/Common/Result/AbstractCrmItem.php +++ b/src/Services/CRM/Common/Result/AbstractCrmItem.php @@ -21,6 +21,10 @@ class AbstractCrmItem extends AbstractItem */ public function __get($offset) { + + var_dump('Зашли в AbstractCrmItem'); + var_dump(__METHOD__); + var_dump($offset); // todo унести в отдельный класс и покрыть тестами // приведение полей к реальным типам данных для основных сущностей CRM switch ($offset) { @@ -55,7 +59,7 @@ public function __get($offset) if ($this->data[$offset] !== '' && $this->data[$offset] !== null) { $var = $this->data[$offset] * 100; - return new Money((string)$var,new Currency('RUB')); + return new Money((string)$var,new Currency('USD')); } return null; case 'IS_MANUAL_OPPORTUNITY': diff --git a/src/Services/CRM/Deal/Result/DealProductRowItemResult.php b/src/Services/CRM/Deal/Result/DealProductRowItemResult.php index e0ddb29a..b0d7af3c 100644 --- a/src/Services/CRM/Deal/Result/DealProductRowItemResult.php +++ b/src/Services/CRM/Deal/Result/DealProductRowItemResult.php @@ -4,8 +4,8 @@ namespace Bitrix24\SDK\Services\CRM\Deal\Result; -use Bitrix24\SDK\Core\Result\AbstractItem; use Bitrix24\SDK\Services\CRM\Common\Result\AbstractCrmItem; +use Money\Currency; use Money\Money; /** @@ -35,4 +35,28 @@ */ class DealProductRowItemResult extends AbstractCrmItem { + private Currency $currency; + + /** + * @param \Money\Currency $currency + */ + public function __construct(array $data,Currency $currency) + { + parent::__construct($data); + $this->currency = $currency; + } + + public function __get($offset) + { + + var_dump('Cтрока сделки'); + var_dump(__METHOD__); + var_dump($offset); + var_dump($this->currency->getCode()); + + return parent::__get($offset); + + + } + } \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealProductRowItemsResult.php b/src/Services/CRM/Deal/Result/DealProductRowItemsResult.php index 125295a5..64bbbcc2 100644 --- a/src/Services/CRM/Deal/Result/DealProductRowItemsResult.php +++ b/src/Services/CRM/Deal/Result/DealProductRowItemsResult.php @@ -33,7 +33,7 @@ public function getProductRows(): array { $res = []; foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $productRow) { - $res[] = new DealProductRowItemResult($productRow); + $res[] = new DealProductRowItemResult($productRow,$this->currency); } return $res; diff --git a/src/Services/CRM/Deal/Service/DealProductRows.php b/src/Services/CRM/Deal/Service/DealProductRows.php index c3867819..40fe4976 100644 --- a/src/Services/CRM/Deal/Service/DealProductRows.php +++ b/src/Services/CRM/Deal/Service/DealProductRows.php @@ -9,6 +9,7 @@ use Bitrix24\SDK\Core\Result\UpdatedItemResult; use Bitrix24\SDK\Services\AbstractService; use Bitrix24\SDK\Services\CRM\Deal\Result\DealProductRowItemsResult; +use Bitrix24\SDK\Services\CRM\Deal\Result\DealResult; use Money\Currency; /** @@ -29,7 +30,7 @@ class DealProductRows extends AbstractService * @throws BaseException * @throws TransportException */ - public function get(int $dealId): DealProductRowItemsResult + public function getStupid(int $dealId, Currency $currency): DealProductRowItemsResult { return new DealProductRowItemsResult( $this->core->call( @@ -38,10 +39,44 @@ public function get(int $dealId): DealProductRowItemsResult 'id' => $dealId, ] ), - new Currency('RUB') + $currency ); } + public function getSmart(int $dealId): DealProductRowItemsResult + { + $deal = new DealResult($this->core->call('crm.deal.get', ['id' => $dealId])); + $currency = new Currency($deal->deal()->CURRENCY_ID); + return new DealProductRowItemsResult( + $this->core->call( + 'crm.deal.productrows.get', + [ + 'id' => $dealId, + ] + ), + $currency + ); + } + public function getSuperSmart(int $dealId): DealProductRowItemsResult + { + /* $deal = new DealResult($this->core->call('crm.deal.get', ['id' => $dealId])); + $currency = new Currency($deal->deal()->CURRENCY_ID); + return new DealProductRowItemsResult( + $this->core->call( + 'crm.deal.productrows.get', + [ + 'id' => $dealId, + ] + ), + $currency + );*/ + // todo Получить сделку и табличную часть за один запрос к Api + } + + public function getSuperSuperSmart(){ + // todo Метод позволяет экономить один запрос если мы уже знаем валюту, а если не знаем то делает этот запрос. + } + /** * Creates or updates product entries inside the specified deal. * diff --git a/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php b/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php index 35696eca..7816fa3e 100644 --- a/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php +++ b/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php @@ -64,19 +64,26 @@ public function testSet(): void */ public function testGet(): void { - $newDealId = $this->dealService->add(['TITLE' => 'test deal'])->getId(); - $this::assertCount(0, $this->dealProductRowsService->get($newDealId)->getProductRows()); + $callCosts = new Money(1050, new Currency('EUR')); + $currencies = new ISOCurrencies(); + + $moneyFormatter = new DecimalMoneyFormatter($currencies); + $newDealId = $this->dealService->add(['TITLE' => 'test deal','CURRENCY_ID'=>$callCosts->getCurrency()->getCode()])->getId(); $this::assertTrue( $this->dealProductRowsService->set( $newDealId, [ [ 'PRODUCT_NAME' => 'qqqq', + 'PRICE'=> $moneyFormatter->format($callCosts), ], ] )->isSuccess() ); - $this::assertCount(1, $this->dealProductRowsService->get($newDealId)->getProductRows()); + $res = $this->dealProductRowsService->getSmart($newDealId); + foreach ($res->getProductRows() as $productRow){ + var_dump($productRow->PRICE); + } } public function setUp(): void From 53b855f8dcf8df022061e945cccf69490cdfc4cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Wed, 24 Aug 2022 16:58:47 +0300 Subject: [PATCH 423/647] -add method getSuperSmart for DealProductRows.php method 2in1(crm.deal.get,crm.deal.productrows.get) --- .../CRM/Common/Result/AbstractCrmItem.php | 5 +-- .../Deal/Result/DealProductRowItemResult.php | 10 +---- .../CRM/Deal/Service/DealProductRows.php | 44 +++++++++++-------- .../CRM/Deal/Service/DealProductRowsTest.php | 2 +- 4 files changed, 29 insertions(+), 32 deletions(-) diff --git a/src/Services/CRM/Common/Result/AbstractCrmItem.php b/src/Services/CRM/Common/Result/AbstractCrmItem.php index 16a8c501..5f75cb10 100644 --- a/src/Services/CRM/Common/Result/AbstractCrmItem.php +++ b/src/Services/CRM/Common/Result/AbstractCrmItem.php @@ -22,9 +22,7 @@ class AbstractCrmItem extends AbstractItem public function __get($offset) { - var_dump('Зашли в AbstractCrmItem'); - var_dump(__METHOD__); - var_dump($offset); + // todo унести в отдельный класс и покрыть тестами // приведение полей к реальным типам данных для основных сущностей CRM switch ($offset) { @@ -56,7 +54,6 @@ public function __get($offset) case 'OPENED': // deal case 'PRICE': - if ($this->data[$offset] !== '' && $this->data[$offset] !== null) { $var = $this->data[$offset] * 100; return new Money((string)$var,new Currency('USD')); diff --git a/src/Services/CRM/Deal/Result/DealProductRowItemResult.php b/src/Services/CRM/Deal/Result/DealProductRowItemResult.php index b0d7af3c..0f3f2716 100644 --- a/src/Services/CRM/Deal/Result/DealProductRowItemResult.php +++ b/src/Services/CRM/Deal/Result/DealProductRowItemResult.php @@ -38,9 +38,10 @@ class DealProductRowItemResult extends AbstractCrmItem private Currency $currency; /** + * @param array $data * @param \Money\Currency $currency */ - public function __construct(array $data,Currency $currency) + public function __construct(array $data, Currency $currency) { parent::__construct($data); $this->currency = $currency; @@ -48,15 +49,8 @@ public function __construct(array $data,Currency $currency) public function __get($offset) { - - var_dump('Cтрока сделки'); - var_dump(__METHOD__); - var_dump($offset); - var_dump($this->currency->getCode()); - return parent::__get($offset); - } } \ No newline at end of file diff --git a/src/Services/CRM/Deal/Service/DealProductRows.php b/src/Services/CRM/Deal/Service/DealProductRows.php index 40fe4976..fcfd21ab 100644 --- a/src/Services/CRM/Deal/Service/DealProductRows.php +++ b/src/Services/CRM/Deal/Service/DealProductRows.php @@ -25,10 +25,10 @@ class DealProductRows extends AbstractService * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_productrows_get.php * * @param int $dealId - * + * @param \Money\Currency $currency * @return DealProductRowItemsResult - * @throws BaseException - * @throws TransportException + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException */ public function getStupid(int $dealId, Currency $currency): DealProductRowItemsResult { @@ -39,10 +39,14 @@ public function getStupid(int $dealId, Currency $currency): DealProductRowItemsR 'id' => $dealId, ] ), - $currency + $currency ); } + /** + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ public function getSmart(int $dealId): DealProductRowItemsResult { $deal = new DealResult($this->core->call('crm.deal.get', ['id' => $dealId])); @@ -57,25 +61,27 @@ public function getSmart(int $dealId): DealProductRowItemsResult $currency ); } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ public function getSuperSmart(int $dealId): DealProductRowItemsResult { - /* $deal = new DealResult($this->core->call('crm.deal.get', ['id' => $dealId])); - $currency = new Currency($deal->deal()->CURRENCY_ID); - return new DealProductRowItemsResult( - $this->core->call( - 'crm.deal.productrows.get', - [ - 'id' => $dealId, - ] - ), - $currency - );*/ + $data = $this->core->call('batch',array( + 'halt'=>0, + 'cmd'=>array( + $deal = new DealResult($this->core->call('crm.deal.get', ['id' => $dealId])), + $dealProductRow = new DealProductRowItemsResult($this->core->call('crm.deal.productrows.get',['id' => $dealId,]),new Currency($deal->deal()->CURRENCY_ID)) + ) + )); + return $dealProductRow; // todo Получить сделку и табличную часть за один запрос к Api } - public function getSuperSuperSmart(){ - // todo Метод позволяет экономить один запрос если мы уже знаем валюту, а если не знаем то делает этот запрос. - } + public function getSuperSuperSmart() + { + // todo Метод позволяет экономить один запрос если мы уже знаем валюту, а если не знаем то делает этот запрос. + } /** * Creates or updates product entries inside the specified deal. @@ -115,7 +121,7 @@ public function set(int $dealId, array $productRows): UpdatedItemResult $this->core->call( 'crm.deal.productrows.set', [ - 'id' => $dealId, + 'id' => $dealId, 'rows' => $productRows, ] ) diff --git a/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php b/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php index 7816fa3e..cf53c493 100644 --- a/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php +++ b/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php @@ -80,7 +80,7 @@ public function testGet(): void ] )->isSuccess() ); - $res = $this->dealProductRowsService->getSmart($newDealId); + $res = $this->dealProductRowsService->getSuperSmart($newDealId); foreach ($res->getProductRows() as $productRow){ var_dump($productRow->PRICE); } From fdcbb218a16a4f56ac75e024166a60d40d747b06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Mon, 29 Aug 2022 12:50:29 +0300 Subject: [PATCH 424/647] =?UTF-8?q?-=D1=82=D0=B5=D0=BF=D0=B5=D1=80=D1=8C?= =?UTF-8?q?=20=D0=B2=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=D0=B5=20AbstarctCrmI?= =?UTF-8?q?tem=20=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=20=D0=BE=D0=B1=D1=80=D0=B0?= =?UTF-8?q?=D1=89=D0=B0=D1=82=D1=8C=D1=81=D1=8F=20=D0=BA=20currency,=20?= =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B8=D0=BB=D1=81=D1=8F=20=D1=8D=D1=82=D0=BE?= =?UTF-8?q?=20=D0=BF=D1=83=D1=82=D0=B5=D0=BC=20=D0=B7=D0=B0=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D0=BE=D0=B1=D0=BB=D0=B0=D1=81=D1=82=D0=B8=20?= =?UTF-8?q?=D0=B2=D0=B8=D0=B4=D0=B8=D0=BC=D0=BE=D1=81=D1=82=D0=B8=20=D1=81?= =?UTF-8?q?=20private=20=D0=BD=D0=B0=20protected=20=D0=B2=20DealProductRow?= =?UTF-8?q?ItemResult.php.(=D0=A2=D0=B0=D0=BA=20=D0=BC=D0=BE=D0=B6=D0=BD?= =?UTF-8?q?=D0=BE=20=D0=B4=D0=B5=D0=BB=D0=B0=D1=82=D1=8C=20=3F)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CRM/Common/Result/AbstractCrmItem.php | 4 ++- .../Deal/Result/DealProductRowItemResult.php | 3 +- .../CRM/Deal/Service/DealProductRows.php | 22 +++++++++---- .../CRM/Deal/Service/DealProductRowsTest.php | 33 ++++++++++++++++++- 4 files changed, 51 insertions(+), 11 deletions(-) diff --git a/src/Services/CRM/Common/Result/AbstractCrmItem.php b/src/Services/CRM/Common/Result/AbstractCrmItem.php index 5f75cb10..abab2784 100644 --- a/src/Services/CRM/Common/Result/AbstractCrmItem.php +++ b/src/Services/CRM/Common/Result/AbstractCrmItem.php @@ -5,6 +5,7 @@ namespace Bitrix24\SDK\Services\CRM\Common\Result; use Bitrix24\SDK\Core\Result\AbstractItem; +use Bitrix24\SDK\Services\CRM\Deal\Result\DealProductRowItemsResult; use Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNotFoundException; use DateTimeImmutable; use Money\Currency; @@ -19,6 +20,7 @@ class AbstractCrmItem extends AbstractItem * * @return bool|\DateTimeImmutable|int|mixed|null */ + public function __get($offset) { @@ -56,7 +58,7 @@ public function __get($offset) case 'PRICE': if ($this->data[$offset] !== '' && $this->data[$offset] !== null) { $var = $this->data[$offset] * 100; - return new Money((string)$var,new Currency('USD')); + return new Money((string)$var,new Currency($this->currency->getCode())); } return null; case 'IS_MANUAL_OPPORTUNITY': diff --git a/src/Services/CRM/Deal/Result/DealProductRowItemResult.php b/src/Services/CRM/Deal/Result/DealProductRowItemResult.php index 0f3f2716..540d161f 100644 --- a/src/Services/CRM/Deal/Result/DealProductRowItemResult.php +++ b/src/Services/CRM/Deal/Result/DealProductRowItemResult.php @@ -35,7 +35,7 @@ */ class DealProductRowItemResult extends AbstractCrmItem { - private Currency $currency; + protected Currency $currency; /** * @param array $data @@ -50,7 +50,6 @@ public function __construct(array $data, Currency $currency) public function __get($offset) { return parent::__get($offset); - } } \ No newline at end of file diff --git a/src/Services/CRM/Deal/Service/DealProductRows.php b/src/Services/CRM/Deal/Service/DealProductRows.php index fcfd21ab..6bbedf6d 100644 --- a/src/Services/CRM/Deal/Service/DealProductRows.php +++ b/src/Services/CRM/Deal/Service/DealProductRows.php @@ -67,14 +67,22 @@ public function getSmart(int $dealId): DealProductRowItemsResult */ public function getSuperSmart(int $dealId): DealProductRowItemsResult { - $data = $this->core->call('batch',array( + $res = $this->core->call('batch',[ 'halt'=>0, - 'cmd'=>array( - $deal = new DealResult($this->core->call('crm.deal.get', ['id' => $dealId])), - $dealProductRow = new DealProductRowItemsResult($this->core->call('crm.deal.productrows.get',['id' => $dealId,]),new Currency($deal->deal()->CURRENCY_ID)) - ) - )); - return $dealProductRow; + 'cmd'=>[ + $deal = new DealResult( $this->core->call('crm.deal.get', ['id' => $dealId])), + $rows = new DealProductRowItemsResult($this->core->call('crm.deal.productrows.get',['id' => $dealId,]),new Currency($deal->deal()->CURRENCY_ID)), + + ], + ]); + return $rows; + /*$data = $res->getResponseData()->getResult(); + $array = $data->getResultData()['result']['deal']['CURRENCY_ID']; + var_dump($array); + return new DealProductRowItemsResult( + $data->getResultData()['result']['deal']['ID'] , + new Currency($array) + );*/ // todo Получить сделку и табличную часть за один запрос к Api } diff --git a/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php b/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php index cf53c493..b2c7accf 100644 --- a/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php +++ b/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php @@ -60,7 +60,6 @@ public function testSet(): void /** * @throws BaseException * @throws TransportException - * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\DealProductRows::get */ public function testGet(): void { @@ -86,9 +85,41 @@ public function testGet(): void } } + /** + * @throws BaseException + * @throws TransportException + */ + public function testBatch():void{ + $callCosts = new Money(1050, new Currency('EUR')); + $currencies = new ISOCurrencies(); + + $moneyFormatter = new DecimalMoneyFormatter($currencies); + $newDealId = $this->dealService->add(['TITLE' => 'test deal','CURRENCY_ID'=>$callCosts->getCurrency()->getCode()])->getId(); + $this::assertTrue( + $this->dealProductRowsService->set( + $newDealId, + [ + [ + 'PRODUCT_NAME' => 'qqqq', + 'PRICE'=> $moneyFormatter->format($callCosts), + ], + ] + )->isSuccess() + ); + $data = $this->core->call('batch',array( + 'halt'=>0, + 'cmd'=>array( + 'deal'=>'crm.deal.get?id='.$newDealId, + 'productrow'=>'crm.deal.productrows.get?ID=$result[deal]['.$newDealId.'][ID]', + ) + )); + print_r($data); + } + public function setUp(): void { $this->dealService = Fabric::getServiceBuilder()->getCRMScope()->deal(); $this->dealProductRowsService = Fabric::getServiceBuilder()->getCRMScope()->dealProductRows(); + $this->core=Fabric::getCore(); } } \ No newline at end of file From 22c4e7099df3849e2fd1a7f72c12b243639e6d7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Tue, 30 Aug 2022 13:39:37 +0300 Subject: [PATCH 425/647] -add method getSuperSuperSmart --- .../CRM/Common/Result/AbstractCrmItem.php | 2 +- .../CRM/Deal/Service/DealProductRows.php | 37 ++++++++++++++++++- .../CRM/Deal/Service/DealProductRowsTest.php | 11 +++--- 3 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/Services/CRM/Common/Result/AbstractCrmItem.php b/src/Services/CRM/Common/Result/AbstractCrmItem.php index abab2784..2d70acde 100644 --- a/src/Services/CRM/Common/Result/AbstractCrmItem.php +++ b/src/Services/CRM/Common/Result/AbstractCrmItem.php @@ -5,7 +5,6 @@ namespace Bitrix24\SDK\Services\CRM\Common\Result; use Bitrix24\SDK\Core\Result\AbstractItem; -use Bitrix24\SDK\Services\CRM\Deal\Result\DealProductRowItemsResult; use Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNotFoundException; use DateTimeImmutable; use Money\Currency; @@ -58,6 +57,7 @@ public function __get($offset) case 'PRICE': if ($this->data[$offset] !== '' && $this->data[$offset] !== null) { $var = $this->data[$offset] * 100; + var_dump($offset); return new Money((string)$var,new Currency($this->currency->getCode())); } return null; diff --git a/src/Services/CRM/Deal/Service/DealProductRows.php b/src/Services/CRM/Deal/Service/DealProductRows.php index 6bbedf6d..9ef44840 100644 --- a/src/Services/CRM/Deal/Service/DealProductRows.php +++ b/src/Services/CRM/Deal/Service/DealProductRows.php @@ -44,8 +44,10 @@ public function getStupid(int $dealId, Currency $currency): DealProductRowItemsR } /** - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @param int $dealId + * @return \Bitrix24\SDK\Services\CRM\Deal\Result\DealProductRowItemsResult * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException */ public function getSmart(int $dealId): DealProductRowItemsResult { @@ -63,7 +65,10 @@ public function getSmart(int $dealId): DealProductRowItemsResult } /** + * @param int $dealId + * @return \Bitrix24\SDK\Services\CRM\Deal\Result\DealProductRowItemsResult * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException */ public function getSuperSmart(int $dealId): DealProductRowItemsResult { @@ -86,8 +91,36 @@ public function getSuperSmart(int $dealId): DealProductRowItemsResult // todo Получить сделку и табличную часть за один запрос к Api } - public function getSuperSuperSmart() + /** + * @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 + */ + public function getSuperSuperSmart(int $dealId, Currency $currency = null): DealProductRowItemsResult { + if ($currency === null){ + $res = $this->core->call('batch',[ + 'halt'=>0, + 'cmd'=>[ + $deal = new DealResult( $this->core->call('crm.deal.get', ['id' => $dealId])), + $rows = new DealProductRowItemsResult($this->core->call('crm.deal.productrows.get',['id' => $dealId,]),new Currency($deal->deal()->CURRENCY_ID)), + + ], + ]); + return $rows; + }else{ + return new DealProductRowItemsResult( + $this->core->call( + 'crm.deal.productrows.get', + [ + 'id' => $dealId, + ] + ), + $currency + ); + } // todo Метод позволяет экономить один запрос если мы уже знаем валюту, а если не знаем то делает этот запрос. } diff --git a/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php b/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php index b2c7accf..3aaf26d6 100644 --- a/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php +++ b/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php @@ -38,7 +38,7 @@ public function testSet(): void $moneyFormatter = new DecimalMoneyFormatter($currencies); $newDealId = $this->dealService->add(['TITLE' => 'test deal'])->getId(); - $this::assertCount(0, $this->dealProductRowsService->get($newDealId)->getProductRows()); + $this::assertCount(0, $this->dealProductRowsService->getSuperSmart($newDealId)->getProductRows()); $this::assertTrue( $this->dealProductRowsService->set( $newDealId, @@ -50,8 +50,8 @@ public function testSet(): void ] )->isSuccess() ); - $this::assertCount(1, $this->dealProductRowsService->get($newDealId)->getProductRows()); - $mas = $this->dealProductRowsService->get($newDealId)->getProductRows()[0]; + $this::assertCount(1, $this->dealProductRowsService->getSuperSmart($newDealId)->getProductRows()); + $mas = $this->dealProductRowsService->getSuperSmart($newDealId)->getProductRows()[0]; $money = $moneyFormatter->format($mas->PRICE); @@ -63,7 +63,7 @@ public function testSet(): void */ public function testGet(): void { - $callCosts = new Money(1050, new Currency('EUR')); + $callCosts = new Money(1050, new Currency('USD')); $currencies = new ISOCurrencies(); $moneyFormatter = new DecimalMoneyFormatter($currencies); @@ -79,7 +79,8 @@ public function testGet(): void ] )->isSuccess() ); - $res = $this->dealProductRowsService->getSuperSmart($newDealId); + $currency = $callCosts->getCurrency(); + $res = $this->dealProductRowsService->getStupid($newDealId,$currency); foreach ($res->getProductRows() as $productRow){ var_dump($productRow->PRICE); } From e42100f5f55be5422dd7425af94718be18114048 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Wed, 31 Aug 2022 13:08:25 +0300 Subject: [PATCH 426/647] -add method getSuperSuperSmart -delete var_dump --- src/Services/CRM/Common/Result/AbstractCrmItem.php | 1 - .../Services/CRM/Deal/Service/DealProductRowsTest.php | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Services/CRM/Common/Result/AbstractCrmItem.php b/src/Services/CRM/Common/Result/AbstractCrmItem.php index 2d70acde..638366df 100644 --- a/src/Services/CRM/Common/Result/AbstractCrmItem.php +++ b/src/Services/CRM/Common/Result/AbstractCrmItem.php @@ -57,7 +57,6 @@ public function __get($offset) case 'PRICE': if ($this->data[$offset] !== '' && $this->data[$offset] !== null) { $var = $this->data[$offset] * 100; - var_dump($offset); return new Money((string)$var,new Currency($this->currency->getCode())); } return null; diff --git a/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php b/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php index 3aaf26d6..e5e92790 100644 --- a/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php +++ b/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php @@ -80,7 +80,7 @@ public function testGet(): void )->isSuccess() ); $currency = $callCosts->getCurrency(); - $res = $this->dealProductRowsService->getStupid($newDealId,$currency); + $res = $this->dealProductRowsService->getSuperSuperSmart($newDealId,$currency); foreach ($res->getProductRows() as $productRow){ var_dump($productRow->PRICE); } From e1037c9df860b8571c4309a46a1d6dd5e37665d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Mon, 5 Sep 2022 20:06:53 +0300 Subject: [PATCH 427/647] - edit composer.json (-delete symfony routing) --- composer.json | 1 - 1 file changed, 1 deletion(-) diff --git a/composer.json b/composer.json index 7485fa08..e09b099d 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,6 @@ "ramsey/uuid": "^4.2.3", "moneyphp/money": "3.* || 4.*", "symfony/serializer": "6.*||^6.1", - "symfony/routing": "^4.4|^5.3|^6.0", "symfony/property-access": "6.* || 6.1.*", "ext-intl": "*" }, From 3c4569892b6eff8d440225effa51e712286fdac4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Mon, 5 Sep 2022 20:41:29 +0300 Subject: [PATCH 428/647] - removed unnecessary files --- .../Services/MixedTest/MixedTest.php | 94 -------------- tests/Unit/Services/TestPerson/Person.php | 35 ------ .../Services/TestPerson/PersonNormalizer.php | 40 ------ tests/Unit/Services/TestPerson/PersonTest.php | 117 ------------------ 4 files changed, 286 deletions(-) delete mode 100644 tests/Integration/Services/MixedTest/MixedTest.php delete mode 100644 tests/Unit/Services/TestPerson/Person.php delete mode 100644 tests/Unit/Services/TestPerson/PersonNormalizer.php delete mode 100644 tests/Unit/Services/TestPerson/PersonTest.php diff --git a/tests/Integration/Services/MixedTest/MixedTest.php b/tests/Integration/Services/MixedTest/MixedTest.php deleted file mode 100644 index b84c223a..00000000 --- a/tests/Integration/Services/MixedTest/MixedTest.php +++ /dev/null @@ -1,94 +0,0 @@ - 'wine', - 'CURRENCY_ID' => 'USD', - 'PRICE' => 100, - 'SORT' => 1 - - ); - $productId1 = $this->productService->add($dataProduct1)->getId(); - - //Создание продукта 2 - $dataProduct2 = array( - - 'NAME' => 'vodka', - 'CURRENCY_ID' => 'USD', - 'PRICE' => 10, - 'SORT' => 4 - - ); - $productId2 = $this->productService->add($dataProduct2)->getId(); - - - //Создание Сделки - $dataDeal1 = array( - 'TITLE' => 'sale of alcohol', - 'CURRENCY_ID' => 'RUB', - ); - $dealId1 = $this->dealServices->add($dataDeal1)->getId(); - - $productsForDeal = array( - - [ - 'PRODUCT_ID' => $productId1, - 'PRICE' => 5000, - 'QUANTITY' => 1 - ], - [ - 'PRODUCT_ID' => $productId2, - 'PRICE' => 500, - 'QUANTITY' => 1 - ] - - ); - - $addProductInDeal = $this->dealProductRows->set($dealId1, $productsForDeal); - - - self::assertEquals($productsForDeal[0]['PRICE'],$this->dealProductRows->get($dealId1)->getCoreResponse()->getResponseData()->getResult()->getResultData()[0]['PRICE']); - self::assertEquals($productsForDeal[1]['PRICE'],$this->dealProductRows->get($dealId1)->getCoreResponse()->getResponseData()->getResult()->getResultData()[1]['PRICE']); - self::assertGreaterThanOrEqual(1, $productId1); - self::assertGreaterThanOrEqual(1, $productId2); - self::assertTrue((bool)$addProductInDeal); - } - - - /** - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException - */ - public function setUp(): void - { - $this->productService = Fabric::getServiceBuilder()->getCRMScope()->product(); - $this->dealServices = Fabric::getServiceBuilder()->getCRMScope()->deal(); - $this->dealProductRows = Fabric::getServiceBuilder()->getCRMScope()->dealProductRows(); - } -} diff --git a/tests/Unit/Services/TestPerson/Person.php b/tests/Unit/Services/TestPerson/Person.php deleted file mode 100644 index 41c3c19f..00000000 --- a/tests/Unit/Services/TestPerson/Person.php +++ /dev/null @@ -1,35 +0,0 @@ -name; - } - - public function getLastName() - { - return $this->lastName; - } - - - // Setters - public function setName($name) - { - $this->name = $name; - } - - public function setLastName($lastName) - { - $this->lastName = $lastName; - } - -} \ No newline at end of file diff --git a/tests/Unit/Services/TestPerson/PersonNormalizer.php b/tests/Unit/Services/TestPerson/PersonNormalizer.php deleted file mode 100644 index c8b386dc..00000000 --- a/tests/Unit/Services/TestPerson/PersonNormalizer.php +++ /dev/null @@ -1,40 +0,0 @@ -normalizer = $normalizer; - } - - /** - * @param Person $object - * @throws \Symfony\Component\Serializer\Exception\ExceptionInterface - */ - public function normalize($object, string $format = null, array $context = []):array - { - $data = $this->normalizer->normalize($object,$format,$context); - return [ - 'name' => 'new_name', - 'lastname' => 'new_lastname', - ]; - } - - public function supportsNormalization($data, string $format = null, array $context = []):bool - { - return $data instanceof Person; - } - - -} \ No newline at end of file diff --git a/tests/Unit/Services/TestPerson/PersonTest.php b/tests/Unit/Services/TestPerson/PersonTest.php deleted file mode 100644 index 5d0b354f..00000000 --- a/tests/Unit/Services/TestPerson/PersonTest.php +++ /dev/null @@ -1,117 +0,0 @@ -setName('Kirill'); - $person->setLastName('Khramov'); - - - - $jsonContent = $serializer->serialize($person, 'json'); - - - self::assertNotEmpty($jsonContent); - echo $jsonContent; // or return it in a Response - } - - /** - * @test - */ - public function DeserializeTest():void{ - $encoders = [new XmlEncoder(), new JsonEncoder()]; - $normalizers = [new ObjectNormalizer()]; - - $serializer = new Serializer($normalizers, $encoders); - - $data = << - Kirill - Khramov - false - - EOF; - - $person = $serializer->deserialize($data, Person::class, 'xml'); - var_dump($person); - self::assertNotEmpty($person); - } - - /** - *@test - */ - public function NormalizePersonTest():void - { - $person = new Person(); - $encoders = [new XmlEncoder(), new JsonEncoder()]; - $normalizers = [new PersonNormalizer()]; - - $serializer = new Serializer($normalizers, $encoders); - - $person->setName('Kirill'); - $person->setLastName('Khramov'); - - $jsonContent = $serializer->serialize($person, 'json'); - self::assertNotEmpty($jsonContent); - echo $jsonContent; - - } - - /** - * @test - * @throws \Symfony\Component\Serializer\Exception\ExceptionInterface - */ - public function NormalizeMoneyTest():void - { - $encoders = [new XmlEncoder(), new JsonEncoder()]; - $normalizers = [new ObjectNormalizer()]; - - $serializer = new Serializer($normalizers, $encoders); - - $dollars = new Money(100, new Currency('USD')); - - $numberFormatter = new \NumberFormatter('en_US', \NumberFormatter::CURRENCY); - $intlFormatter = new IntlMoneyFormatter($numberFormatter, new ISOCurrencies()); - - $moneyFormatter = new AggregateMoneyFormatter([ - 'USD' => $intlFormatter, - ]); - - $money = $moneyFormatter->format($dollars); - $jsonContent = $serializer->normalize($money, null, [AbstractNormalizer::ATTRIBUTES => ['amount']]); - var_dump($jsonContent); - self::assertNotEmpty($money); - } - -} \ No newline at end of file From 5b837e4ee482493c278d8c4d4cea1c1ccf31fceb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Sat, 10 Sep 2022 13:50:45 +0300 Subject: [PATCH 429/647] - edit method --- .../CRM/Deal/Service/DealProductRows.php | 18 +++++++----------- .../CRM/Deal/Service/DealProductRowsTest.php | 3 ++- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/Services/CRM/Deal/Service/DealProductRows.php b/src/Services/CRM/Deal/Service/DealProductRows.php index 9ef44840..e8955c47 100644 --- a/src/Services/CRM/Deal/Service/DealProductRows.php +++ b/src/Services/CRM/Deal/Service/DealProductRows.php @@ -75,19 +75,15 @@ public function getSuperSmart(int $dealId): DealProductRowItemsResult $res = $this->core->call('batch',[ 'halt'=>0, 'cmd'=>[ - $deal = new DealResult( $this->core->call('crm.deal.get', ['id' => $dealId])), - $rows = new DealProductRowItemsResult($this->core->call('crm.deal.productrows.get',['id' => $dealId,]),new Currency($deal->deal()->CURRENCY_ID)), - + 'deal' => sprintf('crm.deal.get?ID=%s', $dealId), + 'rows' => sprintf('crm.deal.productrows.get?ID=%s', $dealId) ], ]); - return $rows; - /*$data = $res->getResponseData()->getResult(); - $array = $data->getResultData()['result']['deal']['CURRENCY_ID']; - var_dump($array); - return new DealProductRowItemsResult( - $data->getResultData()['result']['deal']['ID'] , - new Currency($array) - );*/ + $data = $res->getResponseData()->getResult()->getResultData(); + $currency =$data['result']['deal']['CURRENCY_ID']; + $deal_test_id = $data['result']['deal']['ID']; + // А как нам вернуть DealProductRowItemsResult????(первый параметр принимает coreResponse) + return new DealProductRowItemsResult($deal_test_id,$currency); // todo Получить сделку и табличную часть за один запрос к Api } diff --git a/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php b/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php index e5e92790..887fab9b 100644 --- a/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php +++ b/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php @@ -80,7 +80,7 @@ public function testGet(): void )->isSuccess() ); $currency = $callCosts->getCurrency(); - $res = $this->dealProductRowsService->getSuperSuperSmart($newDealId,$currency); + $res = $this->dealProductRowsService->getSuperSmart($newDealId); foreach ($res->getProductRows() as $productRow){ var_dump($productRow->PRICE); } @@ -117,6 +117,7 @@ public function testBatch():void{ print_r($data); } + public function setUp(): void { $this->dealService = Fabric::getServiceBuilder()->getCRMScope()->deal(); From ba6fbe8dbbe072388976e04ac704d2f198529a51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Sat, 10 Sep 2022 17:21:38 +0300 Subject: [PATCH 430/647] - delete serializer in composer.json and its dependencies - edit method in DealProductRows.php(work) --- composer.json | 2 - .../Deal/Result/DealProductRowItemResult.php | 6 --- .../CRM/Deal/Service/DealProductRows.php | 37 +++++++++---------- .../CRM/Deal/Service/DealProductRowsTest.php | 4 +- 4 files changed, 19 insertions(+), 30 deletions(-) diff --git a/composer.json b/composer.json index e09b099d..af46885c 100644 --- a/composer.json +++ b/composer.json @@ -29,8 +29,6 @@ "symfony/event-dispatcher": "5.4.* || 6.*", "ramsey/uuid": "^4.2.3", "moneyphp/money": "3.* || 4.*", - "symfony/serializer": "6.*||^6.1", - "symfony/property-access": "6.* || 6.1.*", "ext-intl": "*" }, "require-dev": { diff --git a/src/Services/CRM/Deal/Result/DealProductRowItemResult.php b/src/Services/CRM/Deal/Result/DealProductRowItemResult.php index 540d161f..da551122 100644 --- a/src/Services/CRM/Deal/Result/DealProductRowItemResult.php +++ b/src/Services/CRM/Deal/Result/DealProductRowItemResult.php @@ -46,10 +46,4 @@ public function __construct(array $data, Currency $currency) parent::__construct($data); $this->currency = $currency; } - - public function __get($offset) - { - return parent::__get($offset); - } - } \ No newline at end of file diff --git a/src/Services/CRM/Deal/Service/DealProductRows.php b/src/Services/CRM/Deal/Service/DealProductRows.php index e8955c47..d1a37a34 100644 --- a/src/Services/CRM/Deal/Service/DealProductRows.php +++ b/src/Services/CRM/Deal/Service/DealProductRows.php @@ -80,11 +80,8 @@ public function getSuperSmart(int $dealId): DealProductRowItemsResult ], ]); $data = $res->getResponseData()->getResult()->getResultData(); - $currency =$data['result']['deal']['CURRENCY_ID']; - $deal_test_id = $data['result']['deal']['ID']; - // А как нам вернуть DealProductRowItemsResult????(первый параметр принимает coreResponse) - return new DealProductRowItemsResult($deal_test_id,$currency); - // todo Получить сделку и табличную часть за один запрос к Api + $currency = new Currency($data['result']['deal']['CURRENCY_ID']); + return new DealProductRowItemsResult($res,$currency); } /** @@ -100,24 +97,24 @@ public function getSuperSuperSmart(int $dealId, Currency $currency = null): Deal $res = $this->core->call('batch',[ 'halt'=>0, 'cmd'=>[ - $deal = new DealResult( $this->core->call('crm.deal.get', ['id' => $dealId])), - $rows = new DealProductRowItemsResult($this->core->call('crm.deal.productrows.get',['id' => $dealId,]),new Currency($deal->deal()->CURRENCY_ID)), - + 'deal' => sprintf('crm.deal.get?ID=%s', $dealId), + 'rows' => sprintf('crm.deal.productrows.get?ID=%s', $dealId) ], ]); - return $rows; - }else{ - return new DealProductRowItemsResult( - $this->core->call( - 'crm.deal.productrows.get', - [ - 'id' => $dealId, - ] - ), - $currency - ); + $data = $res->getResponseData()->getResult()->getResultData(); + $currency = new Currency($data['result']['deal']['CURRENCY_ID']); + return new DealProductRowItemsResult($res,$currency); } - // todo Метод позволяет экономить один запрос если мы уже знаем валюту, а если не знаем то делает этот запрос. + + return new DealProductRowItemsResult( + $this->core->call( + 'crm.deal.productrows.get', + [ + 'id' => $dealId, + ] + ), + $currency + ); } /** diff --git a/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php b/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php index 887fab9b..d3fb1458 100644 --- a/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php +++ b/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php @@ -63,7 +63,7 @@ public function testSet(): void */ public function testGet(): void { - $callCosts = new Money(1050, new Currency('USD')); + $callCosts = new Money(1050, new Currency('EUR')); $currencies = new ISOCurrencies(); $moneyFormatter = new DecimalMoneyFormatter($currencies); @@ -80,7 +80,7 @@ public function testGet(): void )->isSuccess() ); $currency = $callCosts->getCurrency(); - $res = $this->dealProductRowsService->getSuperSmart($newDealId); + $res = $this->dealProductRowsService->getSuperSuperSmart($newDealId); foreach ($res->getProductRows() as $productRow){ var_dump($productRow->PRICE); } From a05285e19d65e1ee50bb23d358e4ebb29a97eda0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Fri, 30 Sep 2022 16:50:12 +0300 Subject: [PATCH 431/647] - fix error phpstan --- .../CRM/Common/Result/AbstractCrmItem.php | 14 +++++++++++++ .../Deal/Result/DealProductRowItemResult.php | 10 --------- .../CRM/Deal/Service/DealProductRows.php | 21 ------------------- 3 files changed, 14 insertions(+), 31 deletions(-) diff --git a/src/Services/CRM/Common/Result/AbstractCrmItem.php b/src/Services/CRM/Common/Result/AbstractCrmItem.php index 980128b5..23112c8a 100644 --- a/src/Services/CRM/Common/Result/AbstractCrmItem.php +++ b/src/Services/CRM/Common/Result/AbstractCrmItem.php @@ -14,6 +14,20 @@ class AbstractCrmItem extends AbstractItem { private const CRM_USERFIELD_PREFIX = 'UF_CRM_'; + /** + * @var \Money\Currency + */ + private Currency $currency ; + + public function __construct(array $data, Currency $currency = null) + { + parent::__construct($data); + if ($currency !== null){ + $this->currency = $currency; + } + + } + /** * @param int|string $offset * diff --git a/src/Services/CRM/Deal/Result/DealProductRowItemResult.php b/src/Services/CRM/Deal/Result/DealProductRowItemResult.php index da551122..51af99eb 100644 --- a/src/Services/CRM/Deal/Result/DealProductRowItemResult.php +++ b/src/Services/CRM/Deal/Result/DealProductRowItemResult.php @@ -35,15 +35,5 @@ */ class DealProductRowItemResult extends AbstractCrmItem { - protected Currency $currency; - /** - * @param array $data - * @param \Money\Currency $currency - */ - public function __construct(array $data, Currency $currency) - { - parent::__construct($data); - $this->currency = $currency; - } } \ No newline at end of file diff --git a/src/Services/CRM/Deal/Service/DealProductRows.php b/src/Services/CRM/Deal/Service/DealProductRows.php index bd647c57..3ef4e644 100644 --- a/src/Services/CRM/Deal/Service/DealProductRows.php +++ b/src/Services/CRM/Deal/Service/DealProductRows.php @@ -43,27 +43,6 @@ public function getStupid(int $dealId, Currency $currency): DealProductRowItemsR ); } - /** - * @param int $dealId - * @return \Bitrix24\SDK\Services\CRM\Deal\Result\DealProductRowItemsResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException - */ - public function getSmart(int $dealId): DealProductRowItemsResult - { - $deal = new DealResult($this->core->call('crm.deal.get', ['id' => $dealId])); - $currency = new Currency($deal->deal()->CURRENCY_ID); - return new DealProductRowItemsResult( - $this->core->call( - 'crm.deal.productrows.get', - [ - 'id' => $dealId, - ] - ), - $currency - ); - } - /** * @param int $dealId * @return \Bitrix24\SDK\Services\CRM\Deal\Result\DealProductRowItemsResult From c75b49eea485f9a68bdc43efffeeeaf0df25030b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Wed, 19 Oct 2022 22:32:37 +0300 Subject: [PATCH 432/647] =?UTF-8?q?-=20=D0=BF=D0=BE=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=B8=D0=BB=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1=83=20?= =?UTF-8?q?=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D0=B0=20get=20=D0=B2=20=D0=BE?= =?UTF-8?q?=D0=B1=D1=8A=D0=B5=D0=BA=D1=82=D0=B5=20DealProductRowItemsResul?= =?UTF-8?q?t.php=20(=D0=A2=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20=D0=B2=20=D1=82?= =?UTF-8?q?=D0=B5=D1=81=D1=82=D0=B0=D1=85=20=D0=BC=D0=BE=D0=B6=D0=B5=D0=BC?= =?UTF-8?q?=20=D0=B8=20=D1=83=D0=BA=D0=B0=D0=B7=D1=8B=D0=B2=D0=B0=D1=82?= =?UTF-8?q?=D1=8C=20=D0=B2=D0=B0=D0=BB=D1=8E=D1=82=D1=83=20=D0=B8=D0=BB?= =?UTF-8?q?=D0=B8=20=D0=BD=D0=B5=20=D1=83=D0=BA=D0=B0=D0=B7=D1=8B=D0=B2?= =?UTF-8?q?=D0=B0=D1=82=D1=8C).=20-=20=D1=83=D0=B1=D1=80=D0=B0=D0=BB=20?= =?UTF-8?q?=D0=BB=D0=B8=D1=88=D0=BD=D0=B8=D0=B5=20=D0=BC=D0=B5=D1=82=D0=BE?= =?UTF-8?q?=D0=B4=D1=8B=20-=20=D0=BF=D0=BE=D0=BF=D1=80=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20-=20=D0=B4=D0=BE?= =?UTF-8?q?=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20=D0=B2=20AbstractCrmItem.php?= =?UTF-8?q?=20=D0=BE=D1=81=D1=82=D0=B0=D0=BB=D1=8C=D0=BD=D1=8B=D0=B5=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D1=8F=20=D1=81=D0=B2=D1=8F=D0=B7=D0=B0=D0=BD?= =?UTF-8?q?=D0=BD=D1=8B=D0=B5=20=D1=81=20=D0=B4=D0=B5=D0=BD=D1=8C=D0=B3?= =?UTF-8?q?=D0=B0=D0=BC=D0=B8.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CRM/Common/Result/AbstractCrmItem.php | 11 ++-- .../Deal/Result/DealProductRowItemsResult.php | 10 +++- .../CRM/Deal/Service/DealProductRows.php | 54 +++---------------- .../CRM/Deal/Service/DealProductRowsTest.php | 33 ++++++------ 4 files changed, 40 insertions(+), 68 deletions(-) diff --git a/src/Services/CRM/Common/Result/AbstractCrmItem.php b/src/Services/CRM/Common/Result/AbstractCrmItem.php index 23112c8a..f05d6cc8 100644 --- a/src/Services/CRM/Common/Result/AbstractCrmItem.php +++ b/src/Services/CRM/Common/Result/AbstractCrmItem.php @@ -17,12 +17,12 @@ class AbstractCrmItem extends AbstractItem /** * @var \Money\Currency */ - private Currency $currency ; + private Currency $currency; public function __construct(array $data, Currency $currency = null) { parent::__construct($data); - if ($currency !== null){ + if ($currency !== null) { $this->currency = $currency; } @@ -66,10 +66,13 @@ public function __get($offset) case 'HAS_IMOL': case 'OPENED': // deal + case 'PRICE_EXCLUSIVE': + case 'PRICE_NETTO': + case 'PRICE_BRUTTO': case 'PRICE': if ($this->data[$offset] !== '' && $this->data[$offset] !== null) { - $var = $this->data[$offset] * 100; - return new Money((string)$var,new Currency($this->currency->getCode())); + $var = $this->data[$offset] * 100; + return new Money((string)$var, new Currency($this->currency->getCode())); } return null; case 'IS_MANUAL_OPPORTUNITY': diff --git a/src/Services/CRM/Deal/Result/DealProductRowItemsResult.php b/src/Services/CRM/Deal/Result/DealProductRowItemsResult.php index 25b15866..9cf683aa 100644 --- a/src/Services/CRM/Deal/Result/DealProductRowItemsResult.php +++ b/src/Services/CRM/Deal/Result/DealProductRowItemsResult.php @@ -32,8 +32,14 @@ public function __construct(Response $coreResponse,Currency $currency) public function getProductRows(): array { $res = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult()['result']['rows'] as $productRow) { - $res[] = new DealProductRowItemResult($productRow,$this->currency); + if(!empty($this->getCoreResponse()->getResponseData()->getResult()['result']['rows'])) { + foreach ($this->getCoreResponse()->getResponseData()->getResult()['result']['rows'] as $productRow) { + $res[] = new DealProductRowItemResult($productRow, $this->currency); + } + } else { + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $productRow) { + $res[] = new DealProductRowItemResult($productRow, $this->currency); + } } return $res; diff --git a/src/Services/CRM/Deal/Service/DealProductRows.php b/src/Services/CRM/Deal/Service/DealProductRows.php index 3ef4e644..42cacb1d 100644 --- a/src/Services/CRM/Deal/Service/DealProductRows.php +++ b/src/Services/CRM/Deal/Service/DealProductRows.php @@ -24,58 +24,18 @@ class DealProductRows extends AbstractService * * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_productrows_get.php * - * @param int $dealId - * @param \Money\Currency $currency - * @return DealProductRowItemsResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException - */ - public function getStupid(int $dealId, Currency $currency): DealProductRowItemsResult - { - return new DealProductRowItemsResult( - $this->core->call( - 'crm.deal.productrows.get', - [ - 'id' => $dealId, - ] - ), - $currency - ); - } - - /** - * @param int $dealId - * @return \Bitrix24\SDK\Services\CRM\Deal\Result\DealProductRowItemsResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException - */ - public function getSuperSmart(int $dealId): DealProductRowItemsResult - { - $res = $this->core->call('batch',[ - 'halt'=>0, - 'cmd'=>[ - 'deal' => sprintf('crm.deal.get?ID=%s', $dealId), - 'rows' => sprintf('crm.deal.productrows.get?ID=%s', $dealId) - ], - ]); - $data = $res->getResponseData()->getResult(); - $currency = new Currency($data['result']['deal']['CURRENCY_ID']); - return new DealProductRowItemsResult($res,$currency); - } - - /** * @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 */ - public function getSuperSuperSmart(int $dealId, Currency $currency = null): DealProductRowItemsResult + public function get(int $dealId, Currency $currency = null): DealProductRowItemsResult { - if ($currency === null){ - $res = $this->core->call('batch',[ - 'halt'=>0, - 'cmd'=>[ + if ($currency === null) { + $res = $this->core->call('batch', [ + 'halt' => 0, + 'cmd' => [ 'deal' => sprintf('crm.deal.get?ID=%s', $dealId), 'rows' => sprintf('crm.deal.productrows.get?ID=%s', $dealId) ], @@ -84,7 +44,6 @@ public function getSuperSuperSmart(int $dealId, Currency $currency = null): Deal $currency = new Currency($data['result']['deal']['CURRENCY_ID']); return new DealProductRowItemsResult($res,$currency); } - return new DealProductRowItemsResult( $this->core->call( 'crm.deal.productrows.get', @@ -92,10 +51,11 @@ public function getSuperSuperSmart(int $dealId, Currency $currency = null): Deal 'id' => $dealId, ] ), - $currency + $currency ); } + /** * Creates or updates product entries inside the specified deal. * diff --git a/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php b/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php index 42a487e3..2c286da0 100644 --- a/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php +++ b/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php @@ -33,26 +33,24 @@ class DealProductRowsTest extends TestCase public function testSet(): void { - $callCosts = new Money(1050, new Currency('RUB')); + $callCosts = new Money(1050, new Currency('USD')); $currencies = new ISOCurrencies(); $moneyFormatter = new DecimalMoneyFormatter($currencies); $newDealId = $this->dealService->add(['TITLE' => 'test deal'])->getId(); - $this::assertCount(0, $this->dealProductRowsService->getSuperSmart($newDealId)->getProductRows()); + $this::assertCount(5, $this->dealProductRowsService->get($newDealId)->getProductRows()); $this::assertTrue( $this->dealProductRowsService->set( $newDealId, [ [ - 'PRODUCT_NAME' => 'qqqq', - 'PRICE'=> $moneyFormatter->format($callCosts), + 'PRODUCT_NAME' => 'wine', + 'PRICE' => $moneyFormatter->format($callCosts), ], ] )->isSuccess() ); - $this::assertCount(1, $this->dealProductRowsService->getSuperSmart($newDealId)->getProductRows()); - $mas = $this->dealProductRowsService->getSuperSmart($newDealId)->getProductRows()[0]; - $money = $moneyFormatter->format($mas->PRICE); + $this::assertCount(1, $this->dealProductRowsService->get($newDealId)->getProductRows()); } @@ -63,26 +61,31 @@ public function testSet(): void */ public function testGet(): void { - $callCosts = new Money(1050, new Currency('EUR')); + $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(); + $newDealId = $this->dealService->add(['TITLE' => 'test deal', 'CURRENCY_ID' => $callCosts->getCurrency()->getCode()])->getId(); $this::assertTrue( $this->dealProductRowsService->set( $newDealId, [ [ - 'PRODUCT_NAME' => 'qqqq', - 'PRICE'=> $moneyFormatter->format($callCosts), + 'PRODUCT_NAME' => 'wine', + 'PRICE' => $moneyFormatter->format($callCosts), ], ] )->isSuccess() ); $currency = $callCosts->getCurrency(); - $res = $this->dealProductRowsService->getSuperSuperSmart($newDealId); - foreach ($res->getProductRows() as $productRow){ - var_dump($productRow->PRICE); + + $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); } } @@ -90,6 +93,6 @@ public function setUp(): void { $this->dealService = Fabric::getServiceBuilder()->getCRMScope()->deal(); $this->dealProductRowsService = Fabric::getServiceBuilder()->getCRMScope()->dealProductRows(); - $this->core=Fabric::getCore(); + $this->core = Fabric::getCore(); } } \ No newline at end of file From 9a33ff705a1da598f6c65712e28b8d2e16500706 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Sun, 30 Oct 2022 18:51:33 +0300 Subject: [PATCH 433/647] - add bitrix24 interface and bitrix AccountStatus --- composer.json | 7 +- .../Bitrix24AccountInterface.php | 72 +++++++++++++++++++ .../Bitrix24Account/Bitrix24AccountStatus.php | 16 +++++ 3 files changed, 92 insertions(+), 3 deletions(-) create mode 100644 src/Application/Contracts/Bitrix24Account/Bitrix24AccountInterface.php create mode 100644 src/Application/Contracts/Bitrix24Account/Bitrix24AccountStatus.php diff --git a/composer.json b/composer.json index 7a54f0ad..133000e4 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ } ], "require": { - "php": "7.4.*|8.*", + "php": "7.4.*|8.1*", "ext-json": "*", "ext-bcmath": "*", "ext-curl": "*", @@ -28,7 +28,8 @@ "symfony/http-foundation": "5.4.* || 6.*", "symfony/event-dispatcher": "5.4.* || 6.*", "ramsey/uuid": "^4.2.3", - "moneyphp/money": "3.* || 4.*" + "moneyphp/money": "3.* || 4.*", + "symfony/uid": "^6.0" }, "require-dev": { "monolog/monolog": "2.1.*", @@ -63,4 +64,4 @@ "vendor/bin/phpstan analyse --memory-limit 1G" ] } -} \ No newline at end of file +} diff --git a/src/Application/Contracts/Bitrix24Account/Bitrix24AccountInterface.php b/src/Application/Contracts/Bitrix24Account/Bitrix24AccountInterface.php new file mode 100644 index 00000000..dcde72d7 --- /dev/null +++ b/src/Application/Contracts/Bitrix24Account/Bitrix24AccountInterface.php @@ -0,0 +1,72 @@ + Date: Sun, 30 Oct 2022 19:20:07 +0300 Subject: [PATCH 434/647] - edit composer.json and update version php --- composer.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 133000e4..75a22d6b 100644 --- a/composer.json +++ b/composer.json @@ -14,10 +14,14 @@ { "name": "Maxim Mesilov", "homepage": "https://github.com/mesilov/" + }, + { + "name": "Kirill Hramov", + "homepage": "https://github.com/KarlsonComplete" } ], "require": { - "php": "7.4.*|8.1*", + "php": "8.1.*", "ext-json": "*", "ext-bcmath": "*", "ext-curl": "*", From c439a13edbbc1124a4c0e0b2aaec4494034a7c2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Sun, 30 Oct 2022 19:22:25 +0300 Subject: [PATCH 435/647] - update vendor-check.yml (version php -> 8.1) --- .github/workflows/vendor-check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/vendor-check.yml b/.github/workflows/vendor-check.yml index 2ec82413..802c6d45 100644 --- a/.github/workflows/vendor-check.yml +++ b/.github/workflows/vendor-check.yml @@ -19,7 +19,7 @@ jobs: strategy: matrix: php-version: - - "7.4" + - "8.1" dependencies: [ highest ] steps: From a41e2d09d4a5971319acd557babaaf801588d508 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Sun, 30 Oct 2022 19:46:33 +0300 Subject: [PATCH 436/647] - add contracts for bitrix24accountRepository --- composer.json | 5 +- .../Bitrix24AccountRepositoryInterface.php | 73 +++++++++++++++++++ 2 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 src/Application/Contracts/Bitrix24AccountRepositoryInterface.php diff --git a/composer.json b/composer.json index 7a54f0ad..cfa7a525 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,8 @@ "symfony/http-foundation": "5.4.* || 6.*", "symfony/event-dispatcher": "5.4.* || 6.*", "ramsey/uuid": "^4.2.3", - "moneyphp/money": "3.* || 4.*" + "moneyphp/money": "3.* || 4.*", + "symfony/uid": "^6.0" }, "require-dev": { "monolog/monolog": "2.1.*", @@ -63,4 +64,4 @@ "vendor/bin/phpstan analyse --memory-limit 1G" ] } -} \ No newline at end of file +} diff --git a/src/Application/Contracts/Bitrix24AccountRepositoryInterface.php b/src/Application/Contracts/Bitrix24AccountRepositoryInterface.php new file mode 100644 index 00000000..4513bc50 --- /dev/null +++ b/src/Application/Contracts/Bitrix24AccountRepositoryInterface.php @@ -0,0 +1,73 @@ + Date: Sun, 30 Oct 2022 20:25:52 +0300 Subject: [PATCH 437/647] - add SECURITY.md in root folder --- SECURITY.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..96736b8c --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,12 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +| ------- | ------------------ | +| 2.x | :white_check_mark: | +| 1.x | :x: | +| 0.x | :x: | + +## Reporting a Vulnerability +Create issue with vulnerability details \ No newline at end of file From 102c8459510dcc8d5ef4463f28edffa16bf6501c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Mon, 31 Oct 2022 14:07:12 +0300 Subject: [PATCH 438/647] - add new scope code - biconnector. --- src/Core/Credentials/Scope.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Core/Credentials/Scope.php b/src/Core/Credentials/Scope.php index 7a6117bb..123eb06c 100644 --- a/src/Core/Credentials/Scope.php +++ b/src/Core/Credentials/Scope.php @@ -18,6 +18,7 @@ class Scope */ protected array $availableScope = [ 'bizproc', + 'biconnector', 'calendar', 'call', 'cashbox', From d1c1b102157302f864b18dce89475072fe47dd50 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 31 Oct 2022 22:30:11 +0400 Subject: [PATCH 439/647] fix typehint Signed-off-by: mesilov --- CHANGELOG.md | 11 +++++++++++ src/Services/CRM/Contact/Result/ContactItemResult.php | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 12e933af..e81c5a65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # bitrix24-php-sdk change log +## 2.0-beta.1 — 10.11.2022 + +### Added + +### Changed + +### Bugfix +* fix [typehint at ContactItemResult](https://github.com/mesilov/bitrix24-php-sdk/issues/320) + +### etc + ## 2.0-alpha.7 — 8.08.2022 ### Added diff --git a/src/Services/CRM/Contact/Result/ContactItemResult.php b/src/Services/CRM/Contact/Result/ContactItemResult.php index 82293707..e360e3eb 100644 --- a/src/Services/CRM/Contact/Result/ContactItemResult.php +++ b/src/Services/CRM/Contact/Result/ContactItemResult.php @@ -43,7 +43,7 @@ * @property-read DateTimeInterface $DATE_MODIFY * @property-read string $COMPANY_ID * @property-read string $COMPANY_IDS - * @property-read string $LEAD_ID + * @property-read int $LEAD_ID * @property-read string $ORIGINATOR_ID * @property-read string $ORIGIN_ID * @property-read string $ORIGIN_VERSION From 3074277611e7da47eeb9b66cb9b597f33d1cd6a6 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 31 Oct 2022 22:53:27 +0400 Subject: [PATCH 440/647] fix typehint in DealCategoryItemResult Signed-off-by: mesilov --- CHANGELOG.md | 1 + .../CRM/Common/Result/AbstractCrmItem.php | 4 ++++ .../CRM/Deal/Result/DealCategoryItemResult.php | 15 ++++++++------- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e81c5a65..08592589 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ ### Bugfix * fix [typehint at ContactItemResult](https://github.com/mesilov/bitrix24-php-sdk/issues/320) +* fix [return types in DealCategoryItemResult](https://github.com/mesilov/bitrix24-php-sdk/issues/322) ### etc diff --git a/src/Services/CRM/Common/Result/AbstractCrmItem.php b/src/Services/CRM/Common/Result/AbstractCrmItem.php index f05d6cc8..c05d6984 100644 --- a/src/Services/CRM/Common/Result/AbstractCrmItem.php +++ b/src/Services/CRM/Common/Result/AbstractCrmItem.php @@ -49,6 +49,8 @@ public function __get($offset) case 'QUOTE_ID': // productRow case 'OWNER_ID': + // DealCategoryItem + case 'SORT': if ($this->data[$offset] !== '' && $this->data[$offset] !== null) { return (int)$this->data[$offset]; } @@ -78,11 +80,13 @@ public function __get($offset) case 'IS_MANUAL_OPPORTUNITY': case 'CLOSED': case 'IS_NEW': + case 'IS_LOCKED': case 'IS_RECURRING': case 'IS_RETURN_CUSTOMER': case 'IS_REPEATED_APPROACH': return $this->data[$offset] === 'Y'; case 'DATE_CREATE': + case 'CREATED_DATE': case 'DATE_MODIFY': case 'BIRTHDATE': case 'BEGINDATE': diff --git a/src/Services/CRM/Deal/Result/DealCategoryItemResult.php b/src/Services/CRM/Deal/Result/DealCategoryItemResult.php index 4dd57ab7..46d4c239 100644 --- a/src/Services/CRM/Deal/Result/DealCategoryItemResult.php +++ b/src/Services/CRM/Deal/Result/DealCategoryItemResult.php @@ -4,17 +4,18 @@ namespace Bitrix24\SDK\Services\CRM\Deal\Result; -use Bitrix24\SDK\Core\Result\AbstractItem; +use Bitrix24\SDK\Services\CRM\Common\Result\AbstractCrmItem; +use DateTimeImmutable; /** * Class DealItemResult * - * @property int $ID - * @property string $CREATED_DATE - * @property string $NAME - * @property string $IS_LOCKED - * @property string $SORT + * @property int $ID + * @property DateTimeImmutable $CREATED_DATE + * @property string $NAME + * @property bool $IS_LOCKED + * @property int $SORT */ -class DealCategoryItemResult extends AbstractItem +class DealCategoryItemResult extends AbstractCrmItem { } \ No newline at end of file From 01d29e1497cff238618ada95235a11f58b7a8ba3 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 31 Oct 2022 23:16:12 +0400 Subject: [PATCH 441/647] rename batch interface Signed-off-by: mesilov --- CHANGELOG.md | 1 + src/Core/Batch.php | 4 ++-- src/Core/BulkItemsReader/BulkItemsReaderBuilder.php | 12 ++++++------ .../FilterWithBatchWithoutCountOrder.php | 10 +++++----- ...tchInterface.php => BatchOperationsInterface.php} | 4 ++-- src/Services/AbstractBatchService.php | 10 +++++----- src/Services/AbstractServiceBuilder.php | 8 ++++---- src/Services/CRM/Deal/Service/Batch.php | 10 +++++----- src/Services/CRM/Lead/Service/Batch.php | 10 +++++----- tests/Unit/Stubs/NullBatch.php | 4 ++-- tools/PerformanceBenchmarks/ListCommand.php | 4 ++-- 11 files changed, 39 insertions(+), 38 deletions(-) rename src/Core/Contracts/{BatchInterface.php => BatchOperationsInterface.php} (97%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 08592589..43c59228 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Added ### Changed +* ❗️Batch interface `BatchInterface` [renamed](https://github.com/mesilov/bitrix24-php-sdk/issues/324) to `Bitrix24\SDK\Core\Contracts\BatchOperationsInterface` ### Bugfix * fix [typehint at ContactItemResult](https://github.com/mesilov/bitrix24-php-sdk/issues/320) diff --git a/src/Core/Batch.php b/src/Core/Batch.php index 10224162..d4123b87 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -6,7 +6,7 @@ use Bitrix24\SDK\Core\Commands\Command; use Bitrix24\SDK\Core\Commands\CommandCollection; -use Bitrix24\SDK\Core\Contracts\BatchInterface; +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; use Bitrix24\SDK\Core\Contracts\CoreInterface; use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; @@ -23,7 +23,7 @@ * * @package Bitrix24\SDK\Core */ -class Batch implements BatchInterface +class Batch implements BatchOperationsInterface { private CoreInterface $core; private LoggerInterface $logger; diff --git a/src/Core/BulkItemsReader/BulkItemsReaderBuilder.php b/src/Core/BulkItemsReader/BulkItemsReaderBuilder.php index 32e99a0e..0c0fa8ea 100644 --- a/src/Core/BulkItemsReader/BulkItemsReaderBuilder.php +++ b/src/Core/BulkItemsReader/BulkItemsReaderBuilder.php @@ -5,7 +5,7 @@ namespace Bitrix24\SDK\Core\BulkItemsReader; use Bitrix24\SDK\Core\BulkItemsReader\ReadStrategies\FilterWithBatchWithoutCountOrder; -use Bitrix24\SDK\Core\Contracts\BatchInterface; +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; use Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface; use Bitrix24\SDK\Core\Contracts\CoreInterface; use Psr\Log\LoggerInterface; @@ -13,16 +13,16 @@ class BulkItemsReaderBuilder { protected CoreInterface $core; - protected BatchInterface $batch; + protected BatchOperationsInterface $batch; protected LoggerInterface $logger; protected BulkItemsReaderInterface $readStrategy; /** - * @param \Bitrix24\SDK\Core\Contracts\CoreInterface $core - * @param \Bitrix24\SDK\Core\Contracts\BatchInterface $batch - * @param \Psr\Log\LoggerInterface $logger + * @param \Bitrix24\SDK\Core\Contracts\CoreInterface $core + * @param \Bitrix24\SDK\Core\Contracts\BatchOperationsInterface $batch + * @param \Psr\Log\LoggerInterface $logger */ - public function __construct(CoreInterface $core, BatchInterface $batch, LoggerInterface $logger) + public function __construct(CoreInterface $core, BatchOperationsInterface $batch, LoggerInterface $logger) { $this->core = $core; $this->batch = $batch; diff --git a/src/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrder.php b/src/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrder.php index ef58f410..b8eed12d 100644 --- a/src/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrder.php +++ b/src/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrder.php @@ -4,21 +4,21 @@ namespace Bitrix24\SDK\Core\BulkItemsReader\ReadStrategies; -use Bitrix24\SDK\Core\Contracts\BatchInterface; +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; use Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface; use Generator; use Psr\Log\LoggerInterface; class FilterWithBatchWithoutCountOrder implements BulkItemsReaderInterface { - private BatchInterface $batch; + private BatchOperationsInterface $batch; private LoggerInterface $log; /** - * @param \Bitrix24\SDK\Core\Contracts\BatchInterface $batch - * @param \Psr\Log\LoggerInterface $log + * @param \Bitrix24\SDK\Core\Contracts\BatchOperationsInterface $batch + * @param \Psr\Log\LoggerInterface $log */ - public function __construct(BatchInterface $batch, LoggerInterface $log) + public function __construct(BatchOperationsInterface $batch, LoggerInterface $log) { $this->batch = $batch; $this->log = $log; diff --git a/src/Core/Contracts/BatchInterface.php b/src/Core/Contracts/BatchOperationsInterface.php similarity index 97% rename from src/Core/Contracts/BatchInterface.php rename to src/Core/Contracts/BatchOperationsInterface.php index b6f0744e..801beab6 100644 --- a/src/Core/Contracts/BatchInterface.php +++ b/src/Core/Contracts/BatchOperationsInterface.php @@ -9,11 +9,11 @@ use Generator; /** - * Interface BatchInterface + * Interface BatchOperationsInterface * * @package Bitrix24\SDK\Core\Contracts */ -interface BatchInterface +interface BatchOperationsInterface { /** * Batch wrapper for *.list methods without counting elements on every api-call diff --git a/src/Services/AbstractBatchService.php b/src/Services/AbstractBatchService.php index c3d30071..c62a6b69 100644 --- a/src/Services/AbstractBatchService.php +++ b/src/Services/AbstractBatchService.php @@ -4,7 +4,7 @@ namespace Bitrix24\SDK\Services; -use Bitrix24\SDK\Core\Contracts\BatchInterface; +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; use Psr\Log\LoggerInterface; /** @@ -14,16 +14,16 @@ */ abstract class AbstractBatchService { - protected BatchInterface $batch; + protected BatchOperationsInterface $batch; protected LoggerInterface $log; /** * Batch constructor. * - * @param BatchInterface $batch - * @param LoggerInterface $log + * @param BatchOperationsInterface $batch + * @param LoggerInterface $log */ - public function __construct(BatchInterface $batch, LoggerInterface $log) + public function __construct(BatchOperationsInterface $batch, LoggerInterface $log) { $this->batch = $batch; $this->log = $log; diff --git a/src/Services/AbstractServiceBuilder.php b/src/Services/AbstractServiceBuilder.php index 186b5867..36c97565 100644 --- a/src/Services/AbstractServiceBuilder.php +++ b/src/Services/AbstractServiceBuilder.php @@ -5,7 +5,7 @@ namespace Bitrix24\SDK\Services; -use Bitrix24\SDK\Core\Contracts\BatchInterface; +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; use Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface; use Bitrix24\SDK\Core\Contracts\CoreInterface; use Psr\Log\LoggerInterface; @@ -18,7 +18,7 @@ abstract class AbstractServiceBuilder { protected CoreInterface $core; - protected BatchInterface $batch; + protected BatchOperationsInterface $batch; protected BulkItemsReaderInterface $bulkItemsReader; protected LoggerInterface $log; protected array $serviceCache; @@ -27,13 +27,13 @@ abstract class AbstractServiceBuilder * AbstractServiceBuilder constructor. * * @param CoreInterface $core - * @param BatchInterface $batch + * @param BatchOperationsInterface $batch * @param \Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface $bulkItemsReader * @param LoggerInterface $log */ public function __construct( CoreInterface $core, - BatchInterface $batch, + BatchOperationsInterface $batch, BulkItemsReaderInterface $bulkItemsReader, LoggerInterface $log ) { diff --git a/src/Services/CRM/Deal/Service/Batch.php b/src/Services/CRM/Deal/Service/Batch.php index e5351495..6be17a0a 100644 --- a/src/Services/CRM/Deal/Service/Batch.php +++ b/src/Services/CRM/Deal/Service/Batch.php @@ -4,7 +4,7 @@ namespace Bitrix24\SDK\Services\CRM\Deal\Service; -use Bitrix24\SDK\Core\Contracts\BatchInterface; +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Result\AddedItemBatchResult; use Bitrix24\SDK\Core\Result\DeletedItemBatchResult; @@ -20,16 +20,16 @@ */ class Batch { - protected BatchInterface $batch; + protected BatchOperationsInterface $batch; protected LoggerInterface $log; /** * Batch constructor. * - * @param BatchInterface $batch - * @param LoggerInterface $log + * @param BatchOperationsInterface $batch + * @param LoggerInterface $log */ - public function __construct(BatchInterface $batch, LoggerInterface $log) + public function __construct(BatchOperationsInterface $batch, LoggerInterface $log) { $this->batch = $batch; $this->log = $log; diff --git a/src/Services/CRM/Lead/Service/Batch.php b/src/Services/CRM/Lead/Service/Batch.php index 934457c5..e34bdbbb 100644 --- a/src/Services/CRM/Lead/Service/Batch.php +++ b/src/Services/CRM/Lead/Service/Batch.php @@ -4,7 +4,7 @@ namespace Bitrix24\SDK\Services\CRM\Lead\Service; -use Bitrix24\SDK\Core\Contracts\BatchInterface; +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Result\AddedItemBatchResult; use Bitrix24\SDK\Core\Result\DeletedItemBatchResult; @@ -19,16 +19,16 @@ */ class Batch { - protected BatchInterface $batch; + protected BatchOperationsInterface $batch; protected LoggerInterface $log; /** * Batch constructor. * - * @param BatchInterface $batch - * @param LoggerInterface $log + * @param BatchOperationsInterface $batch + * @param LoggerInterface $log */ - public function __construct(BatchInterface $batch, LoggerInterface $log) + public function __construct(BatchOperationsInterface $batch, LoggerInterface $log) { $this->batch = $batch; $this->log = $log; diff --git a/tests/Unit/Stubs/NullBatch.php b/tests/Unit/Stubs/NullBatch.php index 14ddbb6f..f775dab6 100644 --- a/tests/Unit/Stubs/NullBatch.php +++ b/tests/Unit/Stubs/NullBatch.php @@ -4,7 +4,7 @@ namespace Bitrix24\SDK\Tests\Unit\Stubs; -use Bitrix24\SDK\Core\Contracts\BatchInterface; +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Response\DTO\ResponseData; use Generator; @@ -14,7 +14,7 @@ * * @package Bitrix24\SDK\Tests\Unit\Stubs */ -class NullBatch implements BatchInterface +class NullBatch implements BatchOperationsInterface { /** diff --git a/tools/PerformanceBenchmarks/ListCommand.php b/tools/PerformanceBenchmarks/ListCommand.php index 1a5d06f7..a06c78a9 100644 --- a/tools/PerformanceBenchmarks/ListCommand.php +++ b/tools/PerformanceBenchmarks/ListCommand.php @@ -5,7 +5,7 @@ namespace Bitrix24\SDK\Tools\PerformanceBenchmarks; use Bitrix24\SDK\Core\Batch; -use Bitrix24\SDK\Core\Contracts\BatchInterface; +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; use Bitrix24\SDK\Core\Contracts\CoreInterface; use Bitrix24\SDK\Core\CoreBuilder; use Bitrix24\SDK\Core\Credentials\Credentials; @@ -34,7 +34,7 @@ class ListCommand extends Command { protected LoggerInterface $logger; protected CoreInterface $core; - protected BatchInterface $batch; + protected BatchOperationsInterface $batch; /** * @var string */ From 831c13aeac04e95dcf9a43a0260c57131d958870 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 31 Oct 2022 23:33:11 +0400 Subject: [PATCH 442/647] fix contracts for apps Signed-off-by: mesilov --- CHANGELOG.md | 2 ++ .../Bitrix24AccountRepositoryInterface.php | 20 +++++++++---------- 2 files changed, 12 insertions(+), 10 deletions(-) rename src/Application/Contracts/{ => Bitrix24Account}/Bitrix24AccountRepositoryInterface.php (72%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43c59228..91ad69e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ ## 2.0-beta.1 — 10.11.2022 ### Added +* add `Symfony\Component\Uid\Uuid` requirements +* add contracts for bitrix24 applications based on bitrix24-php-sdk - `Bitrix24\SDK\Application\Contracts`, now added `Bitrix24Account` ### Changed * ❗️Batch interface `BatchInterface` [renamed](https://github.com/mesilov/bitrix24-php-sdk/issues/324) to `Bitrix24\SDK\Core\Contracts\BatchOperationsInterface` diff --git a/src/Application/Contracts/Bitrix24AccountRepositoryInterface.php b/src/Application/Contracts/Bitrix24Account/Bitrix24AccountRepositoryInterface.php similarity index 72% rename from src/Application/Contracts/Bitrix24AccountRepositoryInterface.php rename to src/Application/Contracts/Bitrix24Account/Bitrix24AccountRepositoryInterface.php index 4513bc50..deeae92e 100644 --- a/src/Application/Contracts/Bitrix24AccountRepositoryInterface.php +++ b/src/Application/Contracts/Bitrix24Account/Bitrix24AccountRepositoryInterface.php @@ -2,24 +2,24 @@ declare(strict_types=1); -namespace Bitrix24\SDK\Application\Contracts; +namespace Bitrix24\SDK\Application\Contracts\Bitrix24Account; use Symfony\Component\Uid\Uuid; interface Bitrix24AccountRepositoryInterface { /** - * Сохранение аккаунта + * Save account * * @param Bitrix24AccountInterface $entity - * @param bool $flush + * @param bool $flush * * @return void */ public function saveAccount(Bitrix24AccountInterface $entity, bool $flush = false): void; /** - * Получение аккаунта по его идентификатору + * Get by account id * * @param \Symfony\Component\Uid\Uuid $id * @@ -28,24 +28,24 @@ public function saveAccount(Bitrix24AccountInterface $entity, bool $flush = fals public function getById(Uuid $id): Bitrix24AccountInterface; /** - * Физическое удаление аккаунта + * Delete account * * @param Bitrix24AccountInterface $entity - * @param bool $flush + * @param bool $flush * * @return void */ public function deleteAccount(Bitrix24AccountInterface $entity, bool $flush = false): void; /** - * Поиск аккаунта по member_id + * Find account by member_id * * @return ?Bitrix24AccountInterface Returns an array of Bitrix24Account objects */ public function findAccountByMemberId(string $memberId): ?Bitrix24AccountInterface; /** - * Получение аккаунта по member_id + * Get account by member_id * * @param string $memberId * @@ -54,7 +54,7 @@ public function findAccountByMemberId(string $memberId): ?Bitrix24AccountInterfa public function getAccountByMemberId(string $memberId): Bitrix24AccountInterface; /** - * Поиск аккаунта по идентификатору контактного лица + * Find account by contact person id - person, who installed application * * @param \Symfony\Component\Uid\Uuid $contactPersonId * @@ -63,7 +63,7 @@ public function getAccountByMemberId(string $memberId): Bitrix24AccountInterface public function findAccountByContactPersonId(Uuid $contactPersonId): ?Bitrix24AccountInterface; /** - * Поиск аккаунта по URL домена + * Find account by domain url * * @param string $domainUrl * From e1a6ea541f79af93b1c594abf138454eb3f10c3b Mon Sep 17 00:00:00 2001 From: mesilov Date: Tue, 1 Nov 2022 02:15:09 +0400 Subject: [PATCH 443/647] add service builder factory Signed-off-by: mesilov --- CHANGELOG.md | 1 + src/Services/ServiceBuilderFactory.php | 123 +++++++++++++++++++++++++ 2 files changed, 124 insertions(+) create mode 100644 src/Services/ServiceBuilderFactory.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 91ad69e3..6286db57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Added * add `Symfony\Component\Uid\Uuid` requirements * add contracts for bitrix24 applications based on bitrix24-php-sdk - `Bitrix24\SDK\Application\Contracts`, now added `Bitrix24Account` +* add [service builder factory](https://github.com/mesilov/bitrix24-php-sdk/issues/328) ### Changed * ❗️Batch interface `BatchInterface` [renamed](https://github.com/mesilov/bitrix24-php-sdk/issues/324) to `Bitrix24\SDK\Core\Contracts\BatchOperationsInterface` diff --git a/src/Services/ServiceBuilderFactory.php b/src/Services/ServiceBuilderFactory.php new file mode 100644 index 00000000..5bef3253 --- /dev/null +++ b/src/Services/ServiceBuilderFactory.php @@ -0,0 +1,123 @@ +eventDispatcher = $eventDispatcher; + $this->log = $log; + } + + /** + * Init service builder from application account + * + * @param ApplicationProfile $applicationProfile + * @param Bitrix24AccountInterface $bitrix24Account + * + * @return \Bitrix24\SDK\Services\ServiceBuilder + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public function initFromAccount(ApplicationProfile $applicationProfile, Bitrix24AccountInterface $bitrix24Account): ServiceBuilder + { + return $this->getServiceBuilder( + Credentials::createFromOAuth( + AccessToken::initFromArray( + [ + 'access_token' => $bitrix24Account->getAccessToken(), + 'refresh_token' => $bitrix24Account->getRefreshToken(), + 'expires' => $bitrix24Account->getExpires(), + ] + ), + $applicationProfile, + $bitrix24Account->getDomainUrl() + ) + ); + } + + /** + * Init service builder from request + * + * @param \Bitrix24\SDK\Core\Credentials\ApplicationProfile $applicationProfile + * @param \Bitrix24\SDK\Core\Credentials\AccessToken $accessToken + * @param string $bitrix24DomainUrl + * + * @return \Bitrix24\SDK\Services\ServiceBuilder + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public function initFromRequest( + ApplicationProfile $applicationProfile, + AccessToken $accessToken, + string $bitrix24DomainUrl + ): ServiceBuilder { + return $this->getServiceBuilder( + Credentials::createFromOAuth( + $accessToken, + $applicationProfile, + $bitrix24DomainUrl + ) + ); + } + + /** + * Init service builder from webhook + * + * @param string $webhookUrl + * + * @return \Bitrix24\SDK\Services\ServiceBuilder + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public function initFromWebhook(string $webhookUrl): ServiceBuilder + { + return $this->getServiceBuilder(Credentials::createFromWebhook(new WebhookUrl($webhookUrl))); + } + + /** + * @param \Bitrix24\SDK\Core\Credentials\Credentials $credentials + * + * @return \Bitrix24\SDK\Services\ServiceBuilder + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + private function getServiceBuilder(Credentials $credentials): ServiceBuilder + { + $core = (new CoreBuilder()) + ->withEventDispatcher($this->eventDispatcher) + ->withLogger($this->log) + ->withCredentials($credentials) + ->build(); + $batch = new Batch($core, $this->log); + + return new ServiceBuilder( + $core, + $batch, + (new BulkItemsReaderBuilder( + $core, + $batch, + $this->log + ))->build(), + $this->log + ); + } + +} \ No newline at end of file From 0544bc6efad99fef48281a6fd4d33e98b95a6321 Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 23 Nov 2022 12:19:07 +0400 Subject: [PATCH 444/647] add OnVoximplantCallInit and OnVoximplantCallStart Signed-off-by: mesilov --- CHANGELOG.md | 20 +++++-- src/Application/ApplicationStatus.php | 11 ++++ src/Core/Credentials/Scope.php | 8 +++ .../Telephony/Requests/Events/Auth.php | 44 +++++++++++++++ .../Requests/Events/OnVoximplantCallInit.php | 54 ------------------- .../Events/OnVoximplantCallInit/CallData.php | 32 +++++++++++ .../OnVoximplantCallInit.php | 32 +++++++++++ .../Requests/Events/OnVoximplantCallStart.php | 29 ---------- .../Events/OnVoximplantCallStart/CallData.php | 28 ++++++++++ .../OnVoximplantCallStart.php | 29 ++++++++++ .../Application/ApplicationStatusTest.php | 12 ++++- tests/Unit/Core/Credentials/ScopeTest.php | 12 +++++ 12 files changed, 223 insertions(+), 88 deletions(-) create mode 100644 src/Services/Telephony/Requests/Events/Auth.php delete mode 100644 src/Services/Telephony/Requests/Events/OnVoximplantCallInit.php create mode 100644 src/Services/Telephony/Requests/Events/OnVoximplantCallInit/CallData.php create mode 100644 src/Services/Telephony/Requests/Events/OnVoximplantCallInit/OnVoximplantCallInit.php delete mode 100644 src/Services/Telephony/Requests/Events/OnVoximplantCallStart.php create mode 100644 src/Services/Telephony/Requests/Events/OnVoximplantCallStart/CallData.php create mode 100644 src/Services/Telephony/Requests/Events/OnVoximplantCallStart/OnVoximplantCallStart.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 6286db57..9f4e99fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,16 +3,28 @@ ## 2.0-beta.1 — 10.11.2022 ### Added + * add `Symfony\Component\Uid\Uuid` requirements -* add contracts for bitrix24 applications based on bitrix24-php-sdk - `Bitrix24\SDK\Application\Contracts`, now added `Bitrix24Account` +* add contracts for bitrix24 applications based on bitrix24-php-sdk - `Bitrix24\SDK\Application\Contracts`, now added `Bitrix24Account` * add [service builder factory](https://github.com/mesilov/bitrix24-php-sdk/issues/328) +* add method `Bitrix24\SDK\Core\Credentials\Scope::initFromString` +* add method `Bitrix24\SDK\Application\ApplicationStatus::initFromString` ### Changed -* ❗️Batch interface `BatchInterface` [renamed](https://github.com/mesilov/bitrix24-php-sdk/issues/324) to `Bitrix24\SDK\Core\Contracts\BatchOperationsInterface` + +* ❗️Batch interface `BatchInterface` [renamed](https://github.com/mesilov/bitrix24-php-sdk/issues/324) + to `Bitrix24\SDK\Core\Contracts\BatchOperationsInterface` +* ❗`Bitrix24\SDK\Services\Telephony\Requests\Events` moved to separated namespaces: + * from `Bitrix24\SDK\Services\Telephony\Requests\Events\OnVoximplantCallInit` + to `Bitrix24\SDK\Services\Telephony\Requests\Events\OnVoximplantCallInit\OnVoximplantCallInit` + * from `Bitrix24\SDK\Services\Telephony\Requests\Events\OnVoximplantCallStart` + to `Bitrix24\SDK\Services\Telephony\Requests\Events\OnVoximplantCallStart\OnVoximplantCallStart` ### Bugfix + * fix [typehint at ContactItemResult](https://github.com/mesilov/bitrix24-php-sdk/issues/320) * fix [return types in DealCategoryItemResult](https://github.com/mesilov/bitrix24-php-sdk/issues/322) +* fix [add auth node in telephony voximplant events requests](https://github.com/mesilov/bitrix24-php-sdk/issues/331) ### etc @@ -62,10 +74,10 @@ * method `Services\Main\Service::getAllMethods` marks as deprecated * method `Services\Main\Service::getMethodsByScope` marks as deprecated * ❗️fabric methods `Bitrix24\SDK\Core\Credentials` - renamed and now are [consistent](https://github.com/mesilov/bitrix24-php-sdk/issues/303): `createFromWebhook`, `createFromOAuth` + renamed and now are [consistent](https://github.com/mesilov/bitrix24-php-sdk/issues/303): `createFromWebhook`, `createFromOAuth` , `createFromPlacementRequest` * ❗️deleted [unused class](https://github.com/mesilov/bitrix24-php-sdk/issues/303) `Bitrix24\SDK\Core\Response\DTO\ResponseDataCollection` -* ❗️deleted [redundant class](https://github.com/mesilov/bitrix24-php-sdk/issues/303) `Bitrix24\SDK\Core\Response\DTO\Result` +* ❗️deleted [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/Application/ApplicationStatus.php b/src/Application/ApplicationStatus.php index 54500ccf..3fefdbc8 100644 --- a/src/Application/ApplicationStatus.php +++ b/src/Application/ApplicationStatus.php @@ -116,4 +116,15 @@ public static function initFromRequest(Request $request): self { return new self($request->request->getAlpha('status')); } + + /** + * @param string $shortStatusCode + * + * @return static + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public static function initFromString(string $shortStatusCode): self + { + return new self($shortStatusCode); + } } \ No newline at end of file diff --git a/src/Core/Credentials/Scope.php b/src/Core/Credentials/Scope.php index 123eb06c..6e64d1aa 100644 --- a/src/Core/Credentials/Scope.php +++ b/src/Core/Credentials/Scope.php @@ -100,4 +100,12 @@ public function getScopeCodes(): array { return $this->currentScope; } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException + */ + public static function initFromString(string $scope): self + { + return new self(str_replace(' ', '', explode(',', $scope))); + } } \ No newline at end of file diff --git a/src/Services/Telephony/Requests/Events/Auth.php b/src/Services/Telephony/Requests/Events/Auth.php new file mode 100644 index 00000000..b7c2e04a --- /dev/null +++ b/src/Services/Telephony/Requests/Events/Auth.php @@ -0,0 +1,44 @@ + 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), + }; + } +} + + + diff --git a/src/Services/Telephony/Requests/Events/OnVoximplantCallInit.php b/src/Services/Telephony/Requests/Events/OnVoximplantCallInit.php deleted file mode 100644 index 753f2d67..00000000 --- a/src/Services/Telephony/Requests/Events/OnVoximplantCallInit.php +++ /dev/null @@ -1,54 +0,0 @@ -eventPayload['data']['CALL_ID']; - } - - /** - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException - */ - public function getCallType(): CallType - { - return CallType::initByTypeCode((int)$this->eventPayload['data']['CALL_TYPE']); - } - - /** - * @return string Line ID (numeric for leased PBX, regXXX for cloud hosted PBX, and sipXXX for office PBX). - */ - public function getAccountSearchId(): string - { - return $this->eventPayload['data']['ACCOUNT_SEARCH_ID']; - } - - /** - * @return string Number called by the operator (if call type is: 1 – Outbound) or number called by the subscriber (if call type is: 2 – Inbound). - */ - public function getPhoneNumber(): string - { - return $this->eventPayload['data']['PHONE_NUMBER']; - } - - /** - * @return string Line identifier (if call type is: 1 – Outbound) or telephone number used to make a call to the portal (if call type is: 2 – Inbound). - */ - public function getCallerId(): string - { - return $this->eventPayload['data']['CALLER_ID']; - } -} \ No newline at end of file diff --git a/src/Services/Telephony/Requests/Events/OnVoximplantCallInit/CallData.php b/src/Services/Telephony/Requests/Events/OnVoximplantCallInit/CallData.php new file mode 100644 index 00000000..565ed6d7 --- /dev/null +++ b/src/Services/Telephony/Requests/Events/OnVoximplantCallInit/CallData.php @@ -0,0 +1,32 @@ + 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 new file mode 100644 index 00000000..2e0c2889 --- /dev/null +++ b/src/Services/Telephony/Requests/Events/OnVoximplantCallInit/OnVoximplantCallInit.php @@ -0,0 +1,32 @@ +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.php b/src/Services/Telephony/Requests/Events/OnVoximplantCallStart.php deleted file mode 100644 index 11df4201..00000000 --- a/src/Services/Telephony/Requests/Events/OnVoximplantCallStart.php +++ /dev/null @@ -1,29 +0,0 @@ -eventPayload['data']['CALL_ID']; - } - - /** - * @return int Identifier of the user who responded the call. - */ - public function getUserId(): int - { - return (int)$this->eventPayload['data']['USER_ID']; - } -} \ No newline at end of file diff --git a/src/Services/Telephony/Requests/Events/OnVoximplantCallStart/CallData.php b/src/Services/Telephony/Requests/Events/OnVoximplantCallStart/CallData.php new file mode 100644 index 00000000..86a08f01 --- /dev/null +++ b/src/Services/Telephony/Requests/Events/OnVoximplantCallStart/CallData.php @@ -0,0 +1,28 @@ + (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 new file mode 100644 index 00000000..6138ac4f --- /dev/null +++ b/src/Services/Telephony/Requests/Events/OnVoximplantCallStart/OnVoximplantCallStart.php @@ -0,0 +1,29 @@ +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/tests/Unit/Application/ApplicationStatusTest.php b/tests/Unit/Application/ApplicationStatusTest.php index cdf70fb6..d768b0e4 100644 --- a/tests/Unit/Application/ApplicationStatusTest.php +++ b/tests/Unit/Application/ApplicationStatusTest.php @@ -19,7 +19,7 @@ class ApplicationStatusTest extends TestCase * @dataProvider statusDataProvider * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException */ - public function testGetStatusCode(string $shortCode, string $longCode) + public function testGetStatusCode(string $shortCode, string $longCode): void { $this->assertEquals( $longCode, @@ -36,6 +36,16 @@ public function testInvalidStatusCode(): void new ApplicationStatus('foo'); } + /** + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @covers \Bitrix24\SDK\Application\ApplicationStatus::initFromString + */ + public function testInitFromString(): void + { + $this->assertTrue(ApplicationStatus::initFromString('F')->isFree()); + } + /** * @return \Generator */ diff --git a/tests/Unit/Core/Credentials/ScopeTest.php b/tests/Unit/Core/Credentials/ScopeTest.php index 5ffd952d..d7d37b32 100644 --- a/tests/Unit/Core/Credentials/ScopeTest.php +++ b/tests/Unit/Core/Credentials/ScopeTest.php @@ -82,4 +82,16 @@ public function testWrongScopeCode(): void $this->assertEquals(['crm', 'call', 'im'], $scope->getScopeCodes()); } + + /** + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException + * @covers \Bitrix24\SDK\Core\Credentials\Scope::initFromString + * @testdox Test init Scope from string + */ + public function testInitFromString(): void + { + $scope = Scope::initFromString('crm,telephony,call,user_basic,placement,im,imopenlines'); + $this->assertEquals(['crm', 'telephony', 'call', 'user_basic', 'placement', 'im', 'imopenlines'], $scope->getScopeCodes()); + } } From c834b376902d856e7cae3940e00e1835cd2666b8 Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 23 Nov 2022 12:38:23 +0400 Subject: [PATCH 445/647] add OnExternalCallStart Signed-off-by: mesilov --- CHANGELOG.md | 2 + .../Telephony/Requests/Events/Auth.php | 5 +- .../Requests/Events/OnExternalCallStart.php | 95 ------------------- .../Events/OnExternalCallStart/CallData.php | 42 ++++++++ .../OnExternalCallStart.php | 30 ++++++ 5 files changed, 75 insertions(+), 99 deletions(-) delete mode 100644 src/Services/Telephony/Requests/Events/OnExternalCallStart.php create mode 100644 src/Services/Telephony/Requests/Events/OnExternalCallStart/CallData.php create mode 100644 src/Services/Telephony/Requests/Events/OnExternalCallStart/OnExternalCallStart.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f4e99fe..fcdb5b57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ to `Bitrix24\SDK\Services\Telephony\Requests\Events\OnVoximplantCallInit\OnVoximplantCallInit` * from `Bitrix24\SDK\Services\Telephony\Requests\Events\OnVoximplantCallStart` to `Bitrix24\SDK\Services\Telephony\Requests\Events\OnVoximplantCallStart\OnVoximplantCallStart` + * from `Bitrix24\SDK\Services\Telephony\Requests\Events\OnExternalCallStart` + to `Bitrix24\SDK\Services\Telephony\Requests\Events\OnExternalCallStart\OnExternalCallStart` ### Bugfix diff --git a/src/Services/Telephony/Requests/Events/Auth.php b/src/Services/Telephony/Requests/Events/Auth.php index b7c2e04a..a0a3dadd 100644 --- a/src/Services/Telephony/Requests/Events/Auth.php +++ b/src/Services/Telephony/Requests/Events/Auth.php @@ -38,7 +38,4 @@ public function __get($offset) default => parent::__get($offset), }; } -} - - - +} \ No newline at end of file diff --git a/src/Services/Telephony/Requests/Events/OnExternalCallStart.php b/src/Services/Telephony/Requests/Events/OnExternalCallStart.php deleted file mode 100644 index 6361a3c1..00000000 --- a/src/Services/Telephony/Requests/Events/OnExternalCallStart.php +++ /dev/null @@ -1,95 +0,0 @@ -eventPayload['data']['USER_ID']; - } - - /** - * @return string Outbound call ID. - */ - public function getPhoneNumber(): string - { - return $this->eventPayload['data']['PHONE_NUMBER']; - } - - /** - * @return string - */ - public function getPhoneNumberInternational(): string - { - return $this->eventPayload['data']['PHONE_NUMBER_INTERNATIONAL']; - } - - /** - * @return \Bitrix24\SDK\Services\Telephony\Common\CrmEntityType - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException - */ - public function getCrmEntityType(): CrmEntityType - { - return CrmEntityType::initByCode($this->eventPayload['data']['CRM_ENTITY_TYPE']); - } - - /** - * @return int The CRM object ID, which type is specified in CRM_ENTITY_TYPE. - */ - public function getCrmEntityId(): int - { - return (int)$this->eventPayload['data']['CRM_ENTITY_ID']; - } - - /** - * @return int Call list ID, if the call is made from the call list. - */ - public function getCallListId(): int - { - return (int)$this->eventPayload['data']['CALL_LIST_ID']; - } - - /** - * @return string External line number, via which the the call is requested. - */ - public function getLineNumber(): string - { - return $this->eventPayload['data']['LINE_NUMBER']; - } - - /** - * @return string Call ID from the telephony.externalcall.register method. - */ - public function getCallId(): string - { - return $this->eventPayload['data']['CALL_ID']; - } - - /** - * @return string - */ - public function getExtension(): string - { - return $this->eventPayload['data']['EXTENSION']; - } - - /** - * @return bool Defines call as initiated from the mobile app. - */ - public function isMobile(): bool - { - return !($this->eventPayload['data']['IS_MOBILE'] === '0'); - } -} \ No newline at end of file diff --git a/src/Services/Telephony/Requests/Events/OnExternalCallStart/CallData.php b/src/Services/Telephony/Requests/Events/OnExternalCallStart/CallData.php new file mode 100644 index 00000000..6a876d0d --- /dev/null +++ b/src/Services/Telephony/Requests/Events/OnExternalCallStart/CallData.php @@ -0,0 +1,42 @@ + (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 new file mode 100644 index 00000000..a15f1318 --- /dev/null +++ b/src/Services/Telephony/Requests/Events/OnExternalCallStart/OnExternalCallStart.php @@ -0,0 +1,30 @@ +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 From a4152a624e06f7d0bb9c4014baa53b81df2ed68a Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 23 Nov 2022 13:31:32 +0400 Subject: [PATCH 446/647] fix data structure in CallData Signed-off-by: mesilov --- .../Requests/Events/OnVoximplantCallInit/CallData.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Services/Telephony/Requests/Events/OnVoximplantCallInit/CallData.php b/src/Services/Telephony/Requests/Events/OnVoximplantCallInit/CallData.php index 565ed6d7..383db9bb 100644 --- a/src/Services/Telephony/Requests/Events/OnVoximplantCallInit/CallData.php +++ b/src/Services/Telephony/Requests/Events/OnVoximplantCallInit/CallData.php @@ -8,10 +8,13 @@ use Bitrix24\SDK\Services\Telephony\Common\CallType; /** - * @property-read string $CALL_ID - * @property-read string $CALLER_ID - * @property-read int $REST_APP_ID - * @property-read CallType $CALL_TYPE + * @property-read string|null $ACCOUNT_SEARCH_ID Line ID (numeric for leased PBX, regXXX for cloud hosted PBX, and sipXXX for office PBX). + * @property-read string $CALL_ID Call identifier. + * @property-read string|null $PHONE_NUMBER Number called by the operator (if call type is: 1 – Outbound) or number called by the subscriber (if call type is: 2 – Inbound). + * @property-read string $CALLER_ID Line identifier (if call type is: 1 – Outbound) or telephone number used to make a call to the portal (if call type is: 2 – Inbound). + * @property-read int $REST_APP_ID + * @property-read CallType $CALL_TYPE Call type (see Call Type Description). https://training.bitrix24.com/rest_help/scope_telephony/codes_and_types.php#call_type + * @link https://training.bitrix24.com/rest_help/scope_telephony/voximplant/events/onvoximplantcallInit.php */ class CallData extends AbstractItem { From 6a13fee873f4acb4c760706b431aeb77c1dbaa50 Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 23 Nov 2022 13:54:23 +0400 Subject: [PATCH 447/647] add OnVoximplantCallEnd event Signed-off-by: mesilov --- CHANGELOG.md | 2 + .../Requests/Events/OnVoximplantCallEnd.php | 114 ------------------ .../Events/OnVoximplantCallEnd/CallData.php | 66 ++++++++++ .../OnVoximplantCallEnd.php | 35 ++++++ 4 files changed, 103 insertions(+), 114 deletions(-) delete mode 100644 src/Services/Telephony/Requests/Events/OnVoximplantCallEnd.php create mode 100644 src/Services/Telephony/Requests/Events/OnVoximplantCallEnd/CallData.php create mode 100644 src/Services/Telephony/Requests/Events/OnVoximplantCallEnd/OnVoximplantCallEnd.php diff --git a/CHANGELOG.md b/CHANGELOG.md index fcdb5b57..77d49a4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,8 @@ to `Bitrix24\SDK\Services\Telephony\Requests\Events\OnVoximplantCallStart\OnVoximplantCallStart` * from `Bitrix24\SDK\Services\Telephony\Requests\Events\OnExternalCallStart` to `Bitrix24\SDK\Services\Telephony\Requests\Events\OnExternalCallStart\OnExternalCallStart` + * from `Bitrix24\SDK\Services\Telephony\Requests\Events\OnVoximplantCallEnd` + to `Bitrix24\SDK\Services\Telephony\Requests\Events\OnVoximplantCallEnd\OnVoximplantCallEnd` ### Bugfix diff --git a/src/Services/Telephony/Requests/Events/OnVoximplantCallEnd.php b/src/Services/Telephony/Requests/Events/OnVoximplantCallEnd.php deleted file mode 100644 index ff0229f4..00000000 --- a/src/Services/Telephony/Requests/Events/OnVoximplantCallEnd.php +++ /dev/null @@ -1,114 +0,0 @@ -eventPayload['data']['CALL_ID']; - } - - /** - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException - */ - public function getCallType(): CallType - { - return CallType::initByTypeCode((int)$this->eventPayload['data']['CALL_TYPE']); - } - - /** - * @return string Number used by the subscriber to make a call (if call type is: 2 – Inbound) or number called by the operator (if call type is: 1 – Outbound). - */ - public function getPhoneNumber(): string - { - return $this->eventPayload['data']['PHONE_NUMBER']; - } - - /** - * @return string Number receiving the call (if call type is: 2 – Inbound) or number from which the call was made (if call type is: 1 – Outbound). - */ - public function getPortalNumber(): string - { - return $this->eventPayload['data']['PORTAL_NUMBER']; - } - - /** - * @return int Responding operator ID (if call type is: 2 – Inbound) or identifier of the calling operator (if call type is: 1 – Outbound). - */ - public function getPortalUserId(): int - { - return (int)$this->eventPayload['data']['PORTAL_USER_ID']; - } - - /** - * @return int Call duration. - */ - public function getCallDuration(): int - { - return (int)$this->eventPayload['data']['CALL_DURATION']; - } - - /** - * @return \DateTimeImmutable Date in ISO format. - */ - public function getCallStartDate(): DateTimeImmutable - { - return DateTimeImmutable::createFromFormat(DATE_ATOM, $this->eventPayload['data']['CALL_START_DATE']); - } - - /** - * @return \Money\Money Call cost. - */ - public function getCost(): Money - { - if ($this->eventPayload['COST'] === '') { - return new Money(0, new Currency($this->eventPayload['data']['COST_CURRENCY'])); - } - - return (new DecimalMoneyParser(new ISOCurrencies()))->parse( - $this->eventPayload['data']['COST'], - $this->eventPayload['data']['COST_CURRENCY'] - ); - } - - /** - * @return int Call code (See Call Code Table). - */ - public function getCallFailedCode(): int - { - return (int)$this->eventPayload['data']['CALL_FAILED_CODE']; - } - - /** - * @return string Call code textual description (Latin letters). - */ - public function getCallFailedReason(): string - { - return $this->eventPayload['data']['CALL_FAILED_REASON']; - } - - /** - * @return int - */ - public function getCrmActivityId(): int - { - return (int)$this->eventPayload['data']['CRM_ACTIVITY_ID']; - } -} \ No newline at end of file diff --git a/src/Services/Telephony/Requests/Events/OnVoximplantCallEnd/CallData.php b/src/Services/Telephony/Requests/Events/OnVoximplantCallEnd/CallData.php new file mode 100644 index 00000000..de70f004 --- /dev/null +++ b/src/Services/Telephony/Requests/Events/OnVoximplantCallEnd/CallData.php @@ -0,0 +1,66 @@ +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: + 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 new file mode 100644 index 00000000..1b0697ad --- /dev/null +++ b/src/Services/Telephony/Requests/Events/OnVoximplantCallEnd/OnVoximplantCallEnd.php @@ -0,0 +1,35 @@ +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 From b41b1772e7874fc8f3d23d7e50559d4a9dd206b5 Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 23 Nov 2022 20:05:08 +0400 Subject: [PATCH 448/647] add OnVoximplantCallEnd event Signed-off-by: mesilov --- .../Telephony/Requests/Events/OnVoximplantCallEnd/CallData.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Services/Telephony/Requests/Events/OnVoximplantCallEnd/CallData.php b/src/Services/Telephony/Requests/Events/OnVoximplantCallEnd/CallData.php index de70f004..c3a4cc1d 100644 --- a/src/Services/Telephony/Requests/Events/OnVoximplantCallEnd/CallData.php +++ b/src/Services/Telephony/Requests/Events/OnVoximplantCallEnd/CallData.php @@ -39,6 +39,8 @@ class CallData extends AbstractItem public function __get($offset) { switch ($offset) { + case 'CALL_ID': + return (string)$this->data[$offset]; case 'CALL_START_DATE': return new \DateTimeImmutable((string)$this->data[$offset]); case 'CALL_TYPE': From e2aa435cf438fc26c7bc24c35b516abefec9515e Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 23 Nov 2022 20:09:17 +0400 Subject: [PATCH 449/647] fix OnVoximplantCallEnd event Signed-off-by: mesilov --- .../Telephony/Requests/Events/OnVoximplantCallEnd/CallData.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Services/Telephony/Requests/Events/OnVoximplantCallEnd/CallData.php b/src/Services/Telephony/Requests/Events/OnVoximplantCallEnd/CallData.php index c3a4cc1d..b8ddfbd0 100644 --- a/src/Services/Telephony/Requests/Events/OnVoximplantCallEnd/CallData.php +++ b/src/Services/Telephony/Requests/Events/OnVoximplantCallEnd/CallData.php @@ -62,7 +62,7 @@ public function __get($offset) new Currency($this->data['COST_CURRENCY']) ); default: - parent::__get($offset); + return parent::__get($offset); } } } \ No newline at end of file From 43f0f3afb98cc2d99d2e7d6dbeb4257da6f053cf Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 30 Jan 2023 17:30:02 +0400 Subject: [PATCH 450/647] bump php-version Signed-off-by: mesilov --- CHANGELOG.md | 1 + composer.json | 7 +++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 77d49a4c..ea66c7ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ * add [service builder factory](https://github.com/mesilov/bitrix24-php-sdk/issues/328) * add method `Bitrix24\SDK\Core\Credentials\Scope::initFromString` * add method `Bitrix24\SDK\Application\ApplicationStatus::initFromString` +* ❗️add php 8.2 support ### Changed diff --git a/composer.json b/composer.json index 82df0352..e2dc8095 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ } ], "require": { - "php": "8.1.*", + "php": "8.1.* || 8.2.*", "ext-json": "*", "ext-bcmath": "*", "ext-curl": "*", @@ -33,7 +33,7 @@ "symfony/event-dispatcher": "5.4.* || 6.*", "ramsey/uuid": "^4.2.3", "moneyphp/money": "3.* || 4.*", - "symfony/uid": "^6.0", + "symfony/uid": "6.*", "ext-intl": "*" }, "require-dev": { @@ -44,8 +44,7 @@ "phpstan/phpstan": "1.*", "phpunit/phpunit": "9.5.*", "symfony/stopwatch": "5.4.* || 6.*", - "roave/security-advisories": "dev-master", - "ext-intl": "*" + "roave/security-advisories": "dev-master" }, "autoload": { "psr-4": { From 1be62914d99487cf1d3f99772029d5dd49290b0b Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 17 Feb 2023 16:49:58 +0400 Subject: [PATCH 451/647] bump php-version in ci Signed-off-by: mesilov --- .github/workflows/integration.yml | 3 +-- .github/workflows/phpstan.yml | 4 ++-- .github/workflows/phpunit.yml | 3 ++- .github/workflows/vendor-check.yml | 1 + 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 0137cbe9..bb8210c7 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -20,7 +20,7 @@ jobs: strategy: matrix: php-version: - - "7.4" + - "8.1" dependencies: [ highest ] steps: @@ -36,7 +36,6 @@ jobs: ini-values: variables_order=EGPCS env: BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK: ${{ secrets.BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK }} - TEST2_ENV: 12345 - name: "Install dependencies" run: | diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index ea58e758..d2826503 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -13,8 +13,8 @@ jobs: fail-fast: false matrix: php-version: - - "7.4" - - "8.0" + - "8.1" + - "8.2" dependencies: - "lowest" - "highest" diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 725bb64a..e1512640 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -16,7 +16,8 @@ jobs: strategy: matrix: php-version: - - "7.4" + - "8.1" + - "8.2" dependencies: [ highest ] steps: diff --git a/.github/workflows/vendor-check.yml b/.github/workflows/vendor-check.yml index 802c6d45..beaa80f5 100644 --- a/.github/workflows/vendor-check.yml +++ b/.github/workflows/vendor-check.yml @@ -20,6 +20,7 @@ jobs: matrix: php-version: - "8.1" + - "8.2" dependencies: [ highest ] steps: From c939de946451498ba95d57b21539ba8ee83332e8 Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 17 Feb 2023 17:20:44 +0400 Subject: [PATCH 452/647] fix phpdoc Signed-off-by: mesilov --- src/Application/ApplicationStatus.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Application/ApplicationStatus.php b/src/Application/ApplicationStatus.php index 3fefdbc8..fc65ebc4 100644 --- a/src/Application/ApplicationStatus.php +++ b/src/Application/ApplicationStatus.php @@ -20,7 +20,7 @@ class ApplicationStatus /** * @param string $statusShortCode * - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @throws InvalidArgumentException */ public function __construct(string $statusShortCode) { @@ -107,10 +107,10 @@ public function getStatusCode(): string } /** - * @param \Symfony\Component\HttpFoundation\Request $request + * @param Request $request * * @return self - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @throws InvalidArgumentException */ public static function initFromRequest(Request $request): self { @@ -120,8 +120,8 @@ public static function initFromRequest(Request $request): self /** * @param string $shortStatusCode * - * @return static - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @return self + * @throws InvalidArgumentException */ public static function initFromString(string $shortStatusCode): self { From fc98eb51a77d33c6f8257417e86fcb6ef4fd4806 Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 17 Feb 2023 17:27:24 +0400 Subject: [PATCH 453/647] fix undefined index error Signed-off-by: mesilov --- src/Core/ApiClient.php | 46 +++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/src/Core/ApiClient.php b/src/Core/ApiClient.php index 46ab0497..ac7387e0 100644 --- a/src/Core/ApiClient.php +++ b/src/Core/ApiClient.php @@ -6,7 +6,9 @@ use Bitrix24\SDK\Core\Contracts\ApiClientInterface; use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Exceptions\TransportException; use Bitrix24\SDK\Core\Response\DTO\RenewedAccessToken; +use Fig\Http\Message\StatusCodeInterface; use Psr\Log\LoggerInterface; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -31,8 +33,8 @@ class ApiClient implements ApiClientInterface * ApiClient constructor. * * @param Credentials\Credentials $credentials - * @param HttpClientInterface $client - * @param LoggerInterface $logger + * @param HttpClientInterface $client + * @param LoggerInterface $logger */ public function __construct(Credentials\Credentials $credentials, HttpClientInterface $client, LoggerInterface $logger) { @@ -53,11 +55,11 @@ public function __construct(Credentials\Credentials $credentials, HttpClientInte protected function getDefaultHeaders(): array { return [ - 'Accept' => 'application/json', - 'Accept-Charset' => 'utf-8', - 'User-Agent' => sprintf('%s-v-%s-php-%s', self::SDK_USER_AGENT, self::SDK_VERSION, PHP_VERSION), + 'Accept' => 'application/json', + 'Accept-Charset' => 'utf-8', + 'User-Agent' => sprintf('%s-v-%s-php-%s', self::SDK_USER_AGENT, self::SDK_VERSION, PHP_VERSION), 'X-BITRIX24-PHP-SDK-PHP-VERSION' => PHP_VERSION, - 'X-BITRIX24-PHP-SDK-VERSION' => self::SDK_VERSION, + 'X-BITRIX24-PHP-SDK-VERSION' => self::SDK_VERSION, ]; } @@ -74,6 +76,7 @@ public function getCredentials(): Credentials\Credentials * @throws InvalidArgumentException * @throws TransportExceptionInterface * @throws \JsonException + * @throws TransportException */ public function getNewAccessToken(): RenewedAccessToken { @@ -91,8 +94,8 @@ public function getNewAccessToken(): RenewedAccessToken $this::BITRIX24_OAUTH_SERVER_URL, http_build_query( [ - 'grant_type' => 'refresh_token', - 'client_id' => $this->getCredentials()->getApplicationProfile()->getClientId(), + 'grant_type' => 'refresh_token', + 'client_id' => $this->getCredentials()->getApplicationProfile()->getClientId(), 'client_secret' => $this->getCredentials()->getApplicationProfile()->getClientSecret(), 'refresh_token' => $this->getCredentials()->getAccessToken()->getRefreshToken(), ] @@ -103,16 +106,21 @@ public function getNewAccessToken(): RenewedAccessToken 'headers' => $this->getDefaultHeaders(), ]; $response = $this->client->request($method, $url, $requestOptions); - $result = $response->toArray(false); - $newAccessToken = RenewedAccessToken::initFromArray($result); + $responseData = $response->toArray(false); + if ($response->getStatusCode() === StatusCodeInterface::STATUS_OK) { + $newAccessToken = RenewedAccessToken::initFromArray($responseData); - $this->logger->debug('getNewAccessToken.finish'); - - return $newAccessToken; + $this->logger->debug('getNewAccessToken.finish'); + return $newAccessToken; + } + if ($response->getStatusCode() === StatusCodeInterface::STATUS_BAD_REQUEST) { + 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 string $apiMethod * @param array $parameters * * @return ResponseInterface @@ -124,8 +132,8 @@ public function getResponse(string $apiMethod, array $parameters = []): Response $this->logger->info( 'getResponse.start', [ - 'apiMethod' => $apiMethod, - 'domainUrl' => $this->credentials->getDomainUrl(), + 'apiMethod' => $apiMethod, + 'domainUrl' => $this->credentials->getDomainUrl(), 'parameters' => $parameters, ] ); @@ -143,8 +151,8 @@ public function getResponse(string $apiMethod, array $parameters = []): Response } $requestOptions = [ - 'json' => $parameters, - 'headers' => $this->getDefaultHeaders(), + 'json' => $parameters, + 'headers' => $this->getDefaultHeaders(), // disable redirects, try to catch portal change domain name event 'max_redirects' => 0, ]; @@ -153,7 +161,7 @@ public function getResponse(string $apiMethod, array $parameters = []): Response $this->logger->info( 'getResponse.end', [ - 'apiMethod' => $apiMethod, + 'apiMethod' => $apiMethod, 'responseInfo' => $response->getInfo(), ] ); From 5afb67ba4e63acc95449ecce5817ebfd13f98322 Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 17 Feb 2023 17:31:21 +0400 Subject: [PATCH 454/647] remove phpstan check on lowest versions Signed-off-by: mesilov --- .github/workflows/phpstan.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index d2826503..068e9864 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -15,9 +15,7 @@ jobs: php-version: - "8.1" - "8.2" - dependencies: - - "lowest" - - "highest" + dependencies: [ highest ] steps: - name: "Checkout" From 4ef8b63b21014a4591bc854e555e8110464d7a6c Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 17 Feb 2023 21:44:17 +0400 Subject: [PATCH 455/647] add method isError Signed-off-by: mesilov --- CHANGELOG.md | 5 +++-- .../Result/ExternalCallRegisterItemResult.php | 14 +++++++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea66c7ca..355578df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # bitrix24-php-sdk change log -## 2.0-beta.1 — 10.11.2022 +## 2.0-beta.1 — 25.02.2023 ### Added @@ -30,7 +30,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) +* ### etc ## 2.0-alpha.7 — 8.08.2022 diff --git a/src/Services/Telephony/Result/ExternalCallRegisterItemResult.php b/src/Services/Telephony/Result/ExternalCallRegisterItemResult.php index ba8a09c2..ef2759a1 100644 --- a/src/Services/Telephony/Result/ExternalCallRegisterItemResult.php +++ b/src/Services/Telephony/Result/ExternalCallRegisterItemResult.php @@ -16,14 +16,22 @@ 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 ?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 + { + return $this->data['LEAD_CREATION_ERROR'] !== '' && $this->data['LEAD_CREATION_ERROR'] !== null; + } } \ No newline at end of file From 0fe12f11bbbd9a5672153879650cc127cf22d9d6 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 18 Feb 2023 00:00:09 +0400 Subject: [PATCH 456/647] add method isError - fix Signed-off-by: mesilov --- .../Telephony/Result/ExternalCallRegisterItemResult.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Services/Telephony/Result/ExternalCallRegisterItemResult.php b/src/Services/Telephony/Result/ExternalCallRegisterItemResult.php index ef2759a1..9b4796d5 100644 --- a/src/Services/Telephony/Result/ExternalCallRegisterItemResult.php +++ b/src/Services/Telephony/Result/ExternalCallRegisterItemResult.php @@ -32,6 +32,9 @@ class ExternalCallRegisterItemResult extends AbstractItem */ 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 From 5e0fa4778b6ade4700469b9dc37aed5fc734a1fa Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 15 Mar 2023 01:48:19 +0400 Subject: [PATCH 457/647] fix non exists field operating on outdated portals Signed-off-by: mesilov --- src/Core/Response/DTO/Time.php | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/Core/Response/DTO/Time.php b/src/Core/Response/DTO/Time.php index e1302aa1..3e83f84b 100644 --- a/src/Core/Response/DTO/Time.php +++ b/src/Core/Response/DTO/Time.php @@ -33,25 +33,26 @@ class Time /** * Time constructor. * - * @param float $start - * @param float $finish - * @param float $duration - * @param float $processing - * @param float $operating + * @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 + * @param int|null $operatingResetAt */ public function __construct( - float $start, - float $finish, - float $duration, - float $processing, - float $operating, + float $start, + float $finish, + float $duration, + float $processing, + float $operating, DateTimeImmutable $dateStart, DateTimeImmutable $dateFinish, - ?int $operatingResetAt - ) { + ?int $operatingResetAt + ) + { $this->start = $start; $this->finish = $finish; $this->duration = $duration; @@ -139,7 +140,7 @@ public static function initFromResponse(array $response): self (float)$response['finish'], (float)$response['duration'], (float)$response['processing'], - (float)$response['operating'], + array_key_exists('operating', $response) ? (float)$response['operating'] : 0, new DateTimeImmutable($response['date_start']), new DateTimeImmutable($response['date_finish']), $response['operating_reset_at'] ?? null From a9157d71e79a7888db459ed93e641a292c794191 Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 15 Mar 2023 01:54:53 +0400 Subject: [PATCH 458/647] add crm multi-field type Phone Signed-off-by: mesilov --- .../CRM/Common/Result/AbstractCrmItem.php | 37 +++++--- .../Result/SystemFields/Types/Phone.php | 25 +++++ .../SystemFields/Types/PhoneValueType.php | 16 ++++ .../CRM/Contact/Result/ContactItemResult.php | 6 +- src/Services/CRM/Contact/Service/Contact.php | 2 +- .../Services/CRM/PhoneCollectionBuilder.php | 92 +++++++++++++++++++ .../Services/CRM/PhoneNumberBuilder.php | 31 +++++++ 7 files changed, 193 insertions(+), 16 deletions(-) create mode 100644 src/Services/CRM/Common/Result/SystemFields/Types/Phone.php create mode 100644 src/Services/CRM/Common/Result/SystemFields/Types/PhoneValueType.php create mode 100644 tests/Builders/Services/CRM/PhoneCollectionBuilder.php create mode 100644 tests/Builders/Services/CRM/PhoneNumberBuilder.php diff --git a/src/Services/CRM/Common/Result/AbstractCrmItem.php b/src/Services/CRM/Common/Result/AbstractCrmItem.php index c05d6984..05e5f304 100644 --- a/src/Services/CRM/Common/Result/AbstractCrmItem.php +++ b/src/Services/CRM/Common/Result/AbstractCrmItem.php @@ -5,6 +5,8 @@ namespace Bitrix24\SDK\Services\CRM\Common\Result; use Bitrix24\SDK\Core\Result\AbstractItem; +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\Userfield\Exceptions\UserfieldNotFoundException; use DateTimeImmutable; use Money\Currency; @@ -15,7 +17,7 @@ class AbstractCrmItem extends AbstractItem private const CRM_USERFIELD_PREFIX = 'UF_CRM_'; /** - * @var \Money\Currency + * @var Currency */ private Currency $currency; @@ -25,7 +27,6 @@ public function __construct(array $data, Currency $currency = null) if ($currency !== null) { $this->currency = $currency; } - } /** @@ -67,16 +68,6 @@ public function __get($offset) case 'HAS_EMAIL': case 'HAS_IMOL': case 'OPENED': - // deal - case 'PRICE_EXCLUSIVE': - case 'PRICE_NETTO': - case 'PRICE_BRUTTO': - case 'PRICE': - 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 'IS_MANUAL_OPPORTUNITY': case 'CLOSED': case 'IS_NEW': @@ -96,6 +87,26 @@ public function __get($offset) } return null; + // deal + case 'PRICE_EXCLUSIVE': + case 'PRICE_NETTO': + case 'PRICE_BRUTTO': + case 'PRICE': + 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 'PHONE': + if (!$this->isKeyExists($offset)) { + return []; + } + + $items = []; + foreach ($this->data[$offset] as $phone) { + $items[] = new Phone($phone); + } + return $items; default: return $this->data[$offset] ?? null; } @@ -107,7 +118,7 @@ public function __get($offset) * @param string $fieldName * * @return mixed|null - * @throws \Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNotFoundException + * @throws UserfieldNotFoundException */ protected function getKeyWithUserfieldByFieldName(string $fieldName) { diff --git a/src/Services/CRM/Common/Result/SystemFields/Types/Phone.php b/src/Services/CRM/Common/Result/SystemFields/Types/Phone.php new file mode 100644 index 00000000..73763cba --- /dev/null +++ b/src/Services/CRM/Common/Result/SystemFields/Types/Phone.php @@ -0,0 +1,25 @@ + $this->data[$offset], + 'ID' => (int)$this->data['ID'], + 'VALUE_TYPE' => PhoneValueType::from($this->data['VALUE_TYPE']), + default => parent::__get($offset), + }; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Common/Result/SystemFields/Types/PhoneValueType.php b/src/Services/CRM/Common/Result/SystemFields/Types/PhoneValueType.php new file mode 100644 index 00000000..8d9636b4 --- /dev/null +++ b/src/Services/CRM/Common/Result/SystemFields/Types/PhoneValueType.php @@ -0,0 +1,16 @@ + 'N']): AddedItemResult { return new AddedItemResult( - $result = $this->core->call( + $this->core->call( 'crm.contact.add', [ 'fields' => $fields, diff --git a/tests/Builders/Services/CRM/PhoneCollectionBuilder.php b/tests/Builders/Services/CRM/PhoneCollectionBuilder.php new file mode 100644 index 00000000..2dbe6819 --- /dev/null +++ b/tests/Builders/Services/CRM/PhoneCollectionBuilder.php @@ -0,0 +1,92 @@ +phones = []; + $this->phoneNumberBuilder = new PhoneNumberBuilder(); + } + + /** + * @throws Exception + */ + public function withDuplicatePhones(int $duplicatesCount = 1): self + { + $duplicatePhone = $this->phoneNumberBuilder->build(); + + $duplicates = []; + for ($i = 0; $i <= $duplicatesCount; $i++) { + $duplicates[] = new Phone([ + 'ID' => time() + random_int(1, 1000000), + 'VALUE' => $duplicatePhone, + 'VALUE_TYPE' => PhoneValueType::work->value + ]); + } + + $this->phones = array_merge( + [ + new Phone([ + 'ID' => time() + random_int(1, 1000000), + 'VALUE' => $this->phoneNumberBuilder->build(), + 'VALUE_TYPE' => PhoneValueType::work->value + ]) + ], + $duplicates + ); + + return $this; + } + + public function withPhoneLength(int $phoneLength): self + { + $this->phones = [ + new Phone([ + 'ID' => time() + random_int(1, 1000000), + 'VALUE' => $this->phoneNumberBuilder->withLength($phoneLength)->build(), + 'VALUE_TYPE' => PhoneValueType::work->value + ]), + new Phone([ + 'ID' => time() + random_int(1, 1000000), + 'VALUE' => $this->phoneNumberBuilder->withLength(7)->build(), + 'VALUE_TYPE' => PhoneValueType::work->value + ]) + ]; + + return $this; + } + + /** + * @throws Exception + */ + public function build(): array + { + return $this->phones; + } + + public function buildNewPhonesCommand(): array + { + $res = []; + foreach ($this->phones as $phone) { + $res[] = [ + 'VALUE' => $phone->VALUE, + 'VALUE_TYPE' => $phone->VALUE_TYPE->value + ]; + } + return $res; + } +} \ No newline at end of file diff --git a/tests/Builders/Services/CRM/PhoneNumberBuilder.php b/tests/Builders/Services/CRM/PhoneNumberBuilder.php new file mode 100644 index 00000000..bcb14a96 --- /dev/null +++ b/tests/Builders/Services/CRM/PhoneNumberBuilder.php @@ -0,0 +1,31 @@ +length = 7; + } + + public function withLength(int $length): self + { + $this->length = $length; + return $this; + } + + /** + * @throws Exception + */ + public function build(): string + { + return '+7' . substr((string)time(), 2, $this->length) . substr((string)random_int(1000, PHP_INT_MAX), 0, 3); + } +} \ No newline at end of file From 5a87e111a855257d32f3d0aa843859d55ba1587f Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 17 Mar 2023 13:43:33 +0400 Subject: [PATCH 459/647] add users scope Signed-off-by: mesilov --- CHANGELOG.md | 12 +- .../CRM/Common/Result/AbstractCrmItem.php | 6 + src/Services/ServiceBuilder.php | 15 +- src/Services/User/Result/UserItemResult.php | 60 ++++++++ src/Services/User/Result/UserResult.php | 16 +++ src/Services/User/Result/UsersResult.php | 27 ++++ src/Services/User/Service/User.php | 120 ++++++++++++++++ src/Services/User/UserServiceBuilder.php | 25 ++++ .../Services/User/Service/UserTest.php | 132 ++++++++++++++++++ 9 files changed, 411 insertions(+), 2 deletions(-) create mode 100644 src/Services/User/Result/UserItemResult.php create mode 100644 src/Services/User/Result/UserResult.php create mode 100644 src/Services/User/Result/UsersResult.php create mode 100644 src/Services/User/Service/User.php create mode 100644 src/Services/User/UserServiceBuilder.php create mode 100644 tests/Integration/Services/User/Service/UserTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 355578df..94600c47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,14 @@ * add method `Bitrix24\SDK\Core\Credentials\Scope::initFromString` * add method `Bitrix24\SDK\Application\ApplicationStatus::initFromString` * ❗️add php 8.2 support +* add system CRM multi-field type `Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\Phone` +* add scope `user`,`user_basic`,`user_brief`,`user.userfield` and services [add scope user support](https://github.com/mesilov/bitrix24-php-sdk/issues/339) + * `Bitrix24\SDK\Services\User\Service\User::fields` - get user fields + * `Bitrix24\SDK\Services\User\Service\User::current` - get current user + * `Bitrix24\SDK\Services\User\Service\User::add` - add user + * `Bitrix24\SDK\Services\User\Service\User::get` - get user + * `Bitrix24\SDK\Services\User\Service\User::update` - update user + * `Bitrix24\SDK\Services\User\Service\User::search` - search users ### Changed @@ -31,7 +39,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 + ### etc ## 2.0-alpha.7 — 8.08.2022 diff --git a/src/Services/CRM/Common/Result/AbstractCrmItem.php b/src/Services/CRM/Common/Result/AbstractCrmItem.php index c05d6984..eaf28aa5 100644 --- a/src/Services/CRM/Common/Result/AbstractCrmItem.php +++ b/src/Services/CRM/Common/Result/AbstractCrmItem.php @@ -37,6 +37,12 @@ public function __construct(array $data, Currency $currency = null) public function __get($offset) { // todo унести в отдельный класс и покрыть тестами + // учитывать требования + // - поддержка пользовательских полей с пользовательскими типами + // - поддержка пользовательских полей со встроенными типами + // - расширяемость для пользовательских полей в клиентском коде + // - хранение связи поле-тип в аннотациях? + // приведение полей к реальным типам данных для основных сущностей CRM switch ($offset) { case 'ID': diff --git a/src/Services/ServiceBuilder.php b/src/Services/ServiceBuilder.php index ecc0cac0..e603ce1f 100644 --- a/src/Services/ServiceBuilder.php +++ b/src/Services/ServiceBuilder.php @@ -9,6 +9,7 @@ use Bitrix24\SDK\Services\IMOpenLines\IMOpenLinesServiceBuilder; use Bitrix24\SDK\Services\Main\MainServiceBuilder; use Bitrix24\SDK\Services\Telephony\TelephonyServiceBuilder; +use Bitrix24\SDK\Services\User\UserServiceBuilder; use Bitrix24\SDK\Services\UserConsent\UserConsentServiceBuilder; use Bitrix24\SDK\Services\Placement\PlacementServiceBuilder; @@ -68,7 +69,7 @@ public function getMainScope(): MainServiceBuilder } /** - * @return \Bitrix24\SDK\Services\UserConsent\UserConsentServiceBuilder + * @return UserConsentServiceBuilder */ public function getUserConsentScope(): UserConsentServiceBuilder { @@ -79,6 +80,18 @@ public function getUserConsentScope(): UserConsentServiceBuilder return $this->serviceCache[__METHOD__]; } + /** + * @return UserServiceBuilder + */ + public function getUserScope(): UserServiceBuilder + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new UserServiceBuilder($this->core, $this->batch, $this->bulkItemsReader, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + /** * @return PlacementServiceBuilder */ diff --git a/src/Services/User/Result/UserItemResult.php b/src/Services/User/Result/UserItemResult.php new file mode 100644 index 00000000..e8ad00e0 --- /dev/null +++ b/src/Services/User/Result/UserItemResult.php @@ -0,0 +1,60 @@ +data[$offset]; + case 'LAST_LOGIN': + case 'DATE_REGISTER': + case 'UF_EMPLOYMENT_DATE': + if ($this->data[$offset] !== '') { + return DateTimeImmutable::createFromFormat(DATE_ATOM, $this->data[$offset]); + } + break; + case 'IS_ONLINE': + return $this->data[$offset] === 'Y'; + } + + return $this->data[$offset] ?? null; + } +} \ No newline at end of file diff --git a/src/Services/User/Result/UserResult.php b/src/Services/User/Result/UserResult.php new file mode 100644 index 00000000..01e0ee4b --- /dev/null +++ b/src/Services/User/Result/UserResult.php @@ -0,0 +1,16 @@ +getCoreResponse()->getResponseData()->getResult()); + } +} \ No newline at end of file diff --git a/src/Services/User/Result/UsersResult.php b/src/Services/User/Result/UsersResult.php new file mode 100644 index 00000000..a4fff780 --- /dev/null +++ b/src/Services/User/Result/UsersResult.php @@ -0,0 +1,27 @@ +getCoreResponse()->getResponseData()->getResult() as $item) { + $res[] = new UserItemResult($item); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/User/Service/User.php b/src/Services/User/Service/User.php new file mode 100644 index 00000000..80228317 --- /dev/null +++ b/src/Services/User/Service/User.php @@ -0,0 +1,120 @@ +core->call('user.fields')); + } + + /** + * Get current user + * @return UserResult + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/users/user_current.php + */ + public function current(): UserResult + { + return new UserResult($this->core->call('user.current')); + } + + /** + * Invites a user. Available only for users with invitation permissions, usually an administrator. Sends a standard account invitation to the user on success. + * + * @param array $fields = ['ID','XML_ID','ACTIVE','NAME','LAST_NAME','SECOND_NAME','TITLE','EMAIL','PERSONAL_PHONE','WORK_PHONE','WORK_POSITION','WORK_COMPANY','IS_ONLINE','TIME_ZONE','TIMESTAMP_X','TIME_ZONE_OFFSET','DATE_REGISTER','LAST_ACTIVITY_DATE','PERSONAL_PROFESSION','PERSONAL_GENDER','PERSONAL_BIRTHDAY','PERSONAL_PHOTO','PERSONAL_FAX','PERSONAL_MOBILE','PERSONAL_PAGER','PERSONAL_STREET','PERSONAL_MAILBOX','PERSONAL_CITY','PERSONAL_STATE','PERSONAL_ZIP','PERSONAL_COUNTRY','PERSONAL_NOTES','WORK_DEPARTMENT','WORK_WWW','WORK_FAX','WORK_PAGER','WORK_STREET','WORK_MAILBOX','WORK_CITY','WORK_STATE','WORK_ZIP','WORK_COUNTRY','WORK_PROFILE','WORK_LOGO','WORK_NOTES','UF_DEPARTMENT','UF_DISTRICT','UF_SKYPE','UF_SKYPE_LINK','UF_ZOOM','UF_TWITTER','UF_FACEBOOK','UF_LINKEDIN','UF_XING','UF_WEB_SITES','UF_PHONE_INNER','UF_EMPLOYMENT_DATE','UF_TIMEMAN','UF_SKILLS','UF_INTERESTS','USER_TYPE'] + * @param string $messageText + * @return AddedItemResult + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/users/user_add.php + */ + public function add(array $fields, string $messageText = ''): AddedItemResult + { + if (!array_key_exists('EXTRANET', $fields)) { + throw new InvalidArgumentException(sprintf('field EXTRANET is required')); + } + + return new AddedItemResult($this->core->call( + 'user.add', + array_merge( + $fields, + [ + 'MESSAGE_TEXT' => $messageText + ] + ) + )); + } + + /** + * @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 + */ + public function get(array $order, array $filter, bool $isAdminMode = false): UsersResult + { + return new UsersResult($this->core->call('user.get', [ + 'sort' => array_keys($order)[0], + 'order' => array_values($order)[0], + 'filter' => $filter, + 'ADMIN_MODE' => $isAdminMode ? 'true' : 'false' + ])); + } + + /** + * Updates user information. Available only for users with invitation permissions. + * @param int $userId + * @param array $fields + * @return UpdatedItemResult + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/users/user_update.php + */ + public function update(int $userId, array $fields): UpdatedItemResult + { + return new UpdatedItemResult($this->core->call('user.update', array_merge( + $fields, + [ + 'ID' => $userId + ] + ))); + } + + /** + * This method is used to retrieve list of users with expedited personal data search (name, last name, middle name, name of department, position). Works in two modes: Quick mode, via Fulltext Index and slower mode via right LIKE (support is determined automatically). + * + * @param array $filterFields + * @return UsersResult + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/users/user_search.php + */ + public function search(array $filterFields): UsersResult + { + return new UsersResult($this->core->call('user.search', $filterFields)); + } +} \ No newline at end of file diff --git a/src/Services/User/UserServiceBuilder.php b/src/Services/User/UserServiceBuilder.php new file mode 100644 index 00000000..d6977687 --- /dev/null +++ b/src/Services/User/UserServiceBuilder.php @@ -0,0 +1,25 @@ +serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new User($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } +} \ No newline at end of file diff --git a/tests/Integration/Services/User/Service/UserTest.php b/tests/Integration/Services/User/Service/UserTest.php new file mode 100644 index 00000000..e8f0ab26 --- /dev/null +++ b/tests/Integration/Services/User/Service/UserTest.php @@ -0,0 +1,132 @@ +userService->search([ + 'NAME' => 'test', + ]); + $this->assertGreaterThanOrEqual(1, $users->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 + */ + public function testGetWithInternalPhone(): void + { + $this->assertGreaterThanOrEqual( + 1, + $this->userService->get(['ID' => 'ASC'], [ + '!UF_PHONE_INNER' => null + ], true)->getCoreResponse()->getResponseData()->getPagination()->getTotal() + ); + } + + /** + * @covers \Bitrix24\SDK\Services\User\Service\User::get + * @testdox test get users list + * @return void + * @throws BaseException + * @throws TransportException + */ + public function testGet(): void + { + $this->assertGreaterThanOrEqual( + 1, + $this->userService->get(['ID' => 'ASC'], [], true)->getCoreResponse()->getResponseData()->getPagination()->getTotal() + ); + } + + public function testUpdate(): void + { + $newUser = [ + 'NAME' => 'Test', + 'EMAIL' => sprintf('%s.test@test.com', time()), + 'EXTRANET' => 'N', + 'UF_DEPARTMENT' => [1] + ]; + $userId = $this->userService->add($newUser)->getId(); + $this->assertTrue($this->userService->update($userId, ['NAME' => 'Test2'])->isSuccess()); + $this->assertEquals( + 'Test2', + $this->userService->get(['ID' => 'ASC'], [ + 'ID' => $userId + ])->getUsers()[0]->NAME + ); + } + + /** + * @covers \Bitrix24\SDK\Services\User\Service\User::add + * @testdox test add user + * @return void + * @throws BaseException + * @throws TransportException + */ + public function testAdd(): void + { + $newUser = [ + 'NAME' => 'Test', + 'EMAIL' => sprintf('%s.test@test.com', time()), + 'EXTRANET' => 'N', + 'UF_DEPARTMENT' => [1] + ]; + $userId = $this->userService->add($newUser)->getId(); + $this->assertGreaterThanOrEqual(1, $userId); + } + + /** + * @covers \Bitrix24\SDK\Services\User\Service\User::current + * @testdox test get current user + * @return void + * @throws BaseException + * @throws TransportException + */ + 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 + */ + public function testGetUserFields(): void + { + $this->assertIsArray($this->userService->fields()->getFieldsDescription()); + } + + public function setUp(): void + { + $this->userService = Fabric::getServiceBuilder()->getUserScope()->user(); + } +} \ No newline at end of file From e0bd1baf2c6c83717f7a5e0196ef172669592430 Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 17 Mar 2023 15:10:21 +0400 Subject: [PATCH 460/647] move cli commands Signed-off-by: mesilov --- CHANGELOG.md | 1 + {tools/bin => bin}/console | 15 ++--- .../GenerateContactsCommand.php | 34 +++++----- .../PerformanceBenchmarks/ListCommand.php | 18 +++--- .../ShowFieldsDescriptionCommand.php | 62 +++++++++---------- 5 files changed, 62 insertions(+), 68 deletions(-) rename {tools/bin => bin}/console (75%) rename tools/{DemoDataGenerators/CRM/Contacts => Commands}/GenerateContactsCommand.php (90%) rename tools/{ => Commands}/PerformanceBenchmarks/ListCommand.php (98%) rename tools/{ => Commands}/ShowFieldsDescriptionCommand.php (88%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94600c47..34531975 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ * fix errors in `ShowFieldsDescriptionCommand` metadata reader CLI command ### etc +* move CLI entry point to `bin/console` ## 2.0-alpha.7 — 8.08.2022 diff --git a/tools/bin/console b/bin/console similarity index 75% rename from tools/bin/console rename to bin/console index c0c6a43f..86ccde03 100644 --- a/tools/bin/console +++ b/bin/console @@ -1,11 +1,12 @@ #!/usr/bin/env php hasParameterOption('--no-debug', true)) { putenv('APP_DEBUG=' . $_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = '0'); } -(new Dotenv())->bootEnv(dirname(__DIR__) . '/.env'); +(new Dotenv())->bootEnv(dirname(__DIR__) . '/tools/.env'); if ($_SERVER['APP_DEBUG']) { umask(0000); @@ -44,9 +45,9 @@ if ($_SERVER['APP_DEBUG']) { } } -$log = new Logger('demo-data-generator'); +$log = new Logger('bitrix24-php-sdk-cli'); $log->pushHandler(new StreamHandler($_ENV['LOGS_FILE'], (int)$_ENV['LOGS_LEVEL'])); -$log->pushProcessor(new \Monolog\Processor\MemoryUsageProcessor(true, true)); +$log->pushProcessor(new MemoryUsageProcessor(true, true)); $application = new Application(); $application->add(new GenerateContactsCommand($log)); diff --git a/tools/DemoDataGenerators/CRM/Contacts/GenerateContactsCommand.php b/tools/Commands/GenerateContactsCommand.php similarity index 90% rename from tools/DemoDataGenerators/CRM/Contacts/GenerateContactsCommand.php rename to tools/Commands/GenerateContactsCommand.php index baaa96b4..26880314 100644 --- a/tools/DemoDataGenerators/CRM/Contacts/GenerateContactsCommand.php +++ b/tools/Commands/GenerateContactsCommand.php @@ -2,8 +2,10 @@ declare(strict_types=1); -namespace Bitrix24\SDK\Tools\DemoDataGenerators\CRM\Contacts; +namespace Bitrix24\SDK\Tools\Commands; +use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\Command\Command; use Bitrix24\SDK\Core\Batch; use Bitrix24\SDK\Core\BulkItemsReader\BulkItemsReaderBuilder; use Bitrix24\SDK\Core\CoreBuilder; @@ -13,27 +15,23 @@ use Bitrix24\SDK\Services\ServiceBuilder; use InvalidArgumentException; use Psr\Log\LoggerInterface; -use Symfony\Component\Console\Command\Command; + use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; -/** - * Class GenerateContactsCommand - * - * @package Bitrix24\SDK\Tools\DemoDataGenerators\CRM\Contacts - */ +#[AsCommand( + name: 'b24:generate:contacts', + description: 'generate demo-data contacts in CRM', + hidden: false +)] class GenerateContactsCommand extends Command { /** * @var LoggerInterface */ protected LoggerInterface $logger; - /** - * @var string - */ - protected static $defaultName = 'generate:contacts'; protected const CONTACTS_COUNT = 'count'; protected const WEBHOOK_URL = 'webhook'; @@ -76,7 +74,7 @@ protected function configure(): void } /** - * @param \Symfony\Component\Console\Input\InputInterface $input + * @param \Symfony\Component\Console\Input\InputInterface $input * @param \Symfony\Component\Console\Output\OutputInterface $output * * @return void @@ -90,7 +88,7 @@ protected function interact(InputInterface $input, OutputInterface $output): voi } /** - * @param InputInterface $input + * @param InputInterface $input * @param OutputInterface $output * * @return int @@ -159,7 +157,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int ); } $timeEnd = microtime(true); - $io->writeln(sprintf('batch query duration: %s seconds', round($timeEnd - $timeStart, 2)) . PHP_EOL . PHP_EOL); + $io->writeln(GenerateContactsCommand . phpsprintf('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); @@ -194,13 +192,13 @@ protected function generateContacts(int $contactsCount): array $contacts = []; for ($i = 0; $i < $contactsCount; $i++) { $contacts[] = [ - 'NAME' => sprintf('name_%s', $i), - 'LAST_NAME' => sprintf('last_%s', $i), + 'NAME' => sprintf('name_%s', $i), + 'LAST_NAME' => sprintf('last_%s', $i), 'SECOND_NAME' => sprintf('second_%s', $i), - 'PHONE' => [ + 'PHONE' => [ ['VALUE' => sprintf('+7978%s', random_int(1000000, 9999999)), 'VALUE_TYPE' => 'MOBILE'], ], - 'EMAIL' => [ + 'EMAIL' => [ ['VALUE' => sprintf('test-%s@gmail.com', random_int(1000000, 9999999)), 'VALUE_TYPE' => 'WORK'], ], ]; diff --git a/tools/PerformanceBenchmarks/ListCommand.php b/tools/Commands/PerformanceBenchmarks/ListCommand.php similarity index 98% rename from tools/PerformanceBenchmarks/ListCommand.php rename to tools/Commands/PerformanceBenchmarks/ListCommand.php index a06c78a9..88ed9fc0 100644 --- a/tools/PerformanceBenchmarks/ListCommand.php +++ b/tools/Commands/PerformanceBenchmarks/ListCommand.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Bitrix24\SDK\Tools\PerformanceBenchmarks; +namespace Bitrix24\SDK\Tools\Commands\PerformanceBenchmarks; use Bitrix24\SDK\Core\Batch; use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; @@ -24,21 +24,19 @@ use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +use Symfony\Component\Console\Attribute\AsCommand; -/** - * Class ListCommand - * - * @package Bitrix24\SDK\Tools\PerformanceBenchmarks - */ + +#[AsCommand( + name: 'b24:benchmark:list', + description: 'performance benchmark for *.list method', + hidden: false +)] class ListCommand extends Command { protected LoggerInterface $logger; protected CoreInterface $core; protected BatchOperationsInterface $batch; - /** - * @var string - */ - protected static $defaultName = 'benchmark:list'; protected const TIME_PRECISION = 4; protected const SELECT_FIELDS_MODE = 'fields'; protected const ELEMENTS_COUNT = 'count'; diff --git a/tools/ShowFieldsDescriptionCommand.php b/tools/Commands/ShowFieldsDescriptionCommand.php similarity index 88% rename from tools/ShowFieldsDescriptionCommand.php rename to tools/Commands/ShowFieldsDescriptionCommand.php index af6254c9..c24d8733 100644 --- a/tools/ShowFieldsDescriptionCommand.php +++ b/tools/Commands/ShowFieldsDescriptionCommand.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Bitrix24\SDK\Tools; +namespace Bitrix24\SDK\Tools\Commands; use Bitrix24\SDK\Core\Contracts\CoreInterface; use Bitrix24\SDK\Core\CoreBuilder; @@ -18,20 +18,18 @@ use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\ChoiceQuestion; use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\Console\Attribute\AsCommand; -/** - * Class ShowFieldsDescriptionCommand - * - * @package Bitrix24\SDK\Tools\PerformanceBenchmarks - */ + +#[AsCommand( + name: 'b24:util:show-fields-description', + description: 'show entity fields description with table or phpDoc output format', + hidden: false +)] class ShowFieldsDescriptionCommand extends Command { protected LoggerInterface $logger; protected CoreInterface $core; - /** - * @var string - */ - protected static $defaultName = 'util:show-fields-description'; protected const WEBHOOK_URL = 'webhook'; protected const OUTPUT_FORMAT = 'output-format'; @@ -71,7 +69,7 @@ protected function configure(): void } /** - * @param InputInterface $input + * @param InputInterface $input * @param OutputInterface $output * * @return int @@ -160,7 +158,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int /** * @param OutputInterface $output - * @param Response $fields + * @param Response $fields * * @throws BaseException */ @@ -175,7 +173,7 @@ private function showFieldsAsPhpDocFunctionSelectSuggest(OutputInterface $output /** * @param OutputInterface $output - * @param Response $fields + * @param Response $fields * * @throws BaseException */ @@ -183,16 +181,15 @@ private function showFieldsAsPhpDocFunctionProperty(OutputInterface $output, Res { $fieldsList = ['*', '* @param array{']; foreach ($fields->getResponseData()->getResult() as $fieldCode => $fieldDescription) { - switch (strtolower($fieldDescription['type'])) { - case 'integer': - $phpDocType = 'int'; - break; - case 'datetime': - $phpDocType = 'string'; - break; - default: - $phpDocType = 'string'; + if (is_array($fieldDescription)) { + $phpDocType = match (strtolower($fieldDescription['type'])) { + 'integer' => 'int', + default => 'string', + }; + } else { + $phpDocType = 'mixed'; } + $fieldsList[] = sprintf('* %s?: %s,', $fieldCode, $phpDocType); } $fieldsList[] = '* } $fields'; @@ -202,7 +199,7 @@ private function showFieldsAsPhpDocFunctionProperty(OutputInterface $output, Res /** * @param OutputInterface $output - * @param Response $fields + * @param Response $fields * * @throws BaseException */ @@ -210,15 +207,14 @@ private function showFieldsAsPhpDocClassHeader(OutputInterface $output, Response { $fieldsList = ['/**', '*']; foreach ($fields->getResponseData()->getResult() as $fieldCode => $fieldDescription) { - switch (strtolower($fieldDescription['type'])) { - case 'integer': - $phpDocType = 'int'; - break; - case 'datetime': - $phpDocType = 'string'; - break; - default: - $phpDocType = 'string'; + + if (is_array($fieldDescription)) { + $phpDocType = match (strtolower($fieldDescription['type'])) { + 'integer' => 'int', + default => 'string', + }; + } else { + $phpDocType = 'mixed'; } $fieldsList[] = sprintf('* @property-read %s $%s', $phpDocType, $fieldCode); } @@ -228,7 +224,7 @@ private function showFieldsAsPhpDocClassHeader(OutputInterface $output, Response /** * @param OutputInterface $output - * @param Response $fields + * @param Response $fields * * @throws BaseException */ From 6f31b6b50a91d896c65c3f17b1d84b546b2f050a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Sun, 19 Mar 2023 11:32:35 +0300 Subject: [PATCH 461/647] =?UTF-8?q?-=20=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D0=BD=D0=B0=201=20=D1=87=D0=B0=D1=81=D1=82=D1=8C=20=D0=B3?= =?UTF-8?q?=D0=B5=D0=BD=D0=B5=D1=80=D0=B0=D1=86=D0=B8=D0=B8=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=BD=D1=82=D0=B0=D0=BA=D1=82=D0=BE=D0=B2=20=D1=81=20=D0=B4?= =?UTF-8?q?=D0=B2=D1=83=D0=BC=D1=8F=20=D0=B2=D0=B8=D0=B4=D0=B0=D0=BC=D0=B8?= =?UTF-8?q?=20=D1=82=D0=B5=D0=BB=D0=B5=D1=84=D0=BE=D0=BD=D0=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../OperatingTimingTest.php | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 tests/Integration/OperatingTimingTest/OperatingTimingTest.php diff --git a/tests/Integration/OperatingTimingTest/OperatingTimingTest.php b/tests/Integration/OperatingTimingTest/OperatingTimingTest.php new file mode 100644 index 00000000..60cf7dbe --- /dev/null +++ b/tests/Integration/OperatingTimingTest/OperatingTimingTest.php @@ -0,0 +1,70 @@ + sprintf('first_%s', time()), + 'SECOND' => sprintf('second_%s', time()), + 'PHONE' => [ + [ + 'VALUE' => $phoneNumberWork, + 'VALUE_TYPE' => 'WORK' + ], + [ + 'VALUE' => $phoneNumberHome, + 'VALUE_TYPE' => 'HOME' + ] + ] + ]; + + } + foreach ($masContacts as $contact){ + var_dump($contact); + $contactId[] = $this->contactService->add($contact)->getId(); + foreach ($contactId as $id){ + $contactUpdate= $this->contactService->update($id,['PHONE'[0] => '']); + } + + self::assertGreaterThanOrEqual(1,$contactId); + } + var_dump($contactId); + + + } + + public function setUp(): void + { + $this->contactService = Fabric::getServiceBuilder()->getCRMScope()->contact(); + } +} \ No newline at end of file From 9009ce586b1ecde48d8e6d71c4d74079bce6a012 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Wed, 22 Mar 2023 16:55:23 +0300 Subject: [PATCH 462/647] =?UTF-8?q?-=20=D0=90=D0=BF=D0=B4=D0=B5=D0=B9?= =?UTF-8?q?=D1=82=20=D0=B1=D0=B5=D0=B7=20=D0=B1=D0=B0=D1=82=D1=87=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../OperatingTimingTest.php | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/tests/Integration/OperatingTimingTest/OperatingTimingTest.php b/tests/Integration/OperatingTimingTest/OperatingTimingTest.php index 60cf7dbe..2a676b40 100644 --- a/tests/Integration/OperatingTimingTest/OperatingTimingTest.php +++ b/tests/Integration/OperatingTimingTest/OperatingTimingTest.php @@ -4,6 +4,7 @@ namespace Bitrix24\SDK\Tests\Integration\OperatingTimingTest; +use Bitrix24\SDK\Core\Batch; use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Exceptions\TransportException; use Bitrix24\SDK\Services\CRM\Contact\Service\Contact; @@ -19,52 +20,51 @@ class OperatingTimingTest extends TestCase { protected Contact $contactService; + private Batch $batch; /** * @throws \Bitrix24\SDK\Core\Exceptions\TransportException * @throws \Bitrix24\SDK\Core\Exceptions\BaseException */ - public function testOperatingTiming() + public function testOperatingTiming(): void { - $PhoneNumWorkMas = []; - $PhoneNumHomeMas = []; $masContacts = []; - for($i=0; $i<5; $i++){ + for ($i = 0; $i < 5; $i++) { $phoneNumberWork = sprintf('+7%s', time()); $phoneNumberHome = sprintf('%s', microtime()); - $phoneNumberHome = implode("-",str_split(substr($phoneNumberHome,2,-13),2)); + $phoneNumberHome = implode("-", str_split(substr($phoneNumberHome, 2, -13), 2)); $masContacts[] = [ - 'NAME' => sprintf('first_%s', time()), - 'SECOND' => sprintf('second_%s', time()), - 'PHONE' => [ - [ - 'VALUE' => $phoneNumberWork, - 'VALUE_TYPE' => 'WORK' + 'fields' => [ + 'NAME' => sprintf('first_%s', time()), + 'SECOND' => sprintf('second_%s', time()), + 'PHONE' => [ + [ + 'VALUE' => $phoneNumberWork, + 'VALUE_TYPE' => 'WORK' + ], + [ + 'VALUE' => $phoneNumberHome, + 'VALUE_TYPE' => 'HOME' + ] ], - [ - 'VALUE' => $phoneNumberHome, - 'VALUE_TYPE' => 'HOME' - ] ] ]; } - foreach ($masContacts as $contact){ - var_dump($contact); - $contactId[] = $this->contactService->add($contact)->getId(); - foreach ($contactId as $id){ - $contactUpdate= $this->contactService->update($id,['PHONE'[0] => '']); - } - - self::assertGreaterThanOrEqual(1,$contactId); + $contactsIdList = []; + foreach ($this->batch->addEntityItems('crm.contact.add', $masContacts) as $addContactResult) { + $contactsIdList[] = $addContactResult->getResult(); } - var_dump($contactId); - - + foreach ($contactsIdList as $contactId) { + $contactPhoneId = $this->contactService->get($contactId[0])->contact()->PHONE[0]['ID']; + $contactUpdate = $this->contactService->update((int)$contactId[0],['PHONE' => [['ID' => $contactPhoneId, 'VALUE' => ""]]],[ "REGISTER_SONET_EVENT" => "Y"]); + } + $this->assertCount(5, $contactsIdList); } public function setUp(): void { + $this->batch = Fabric::getBatchService(); $this->contactService = Fabric::getServiceBuilder()->getCRMScope()->contact(); } } \ No newline at end of file From 0d4b2fdcd9ae4caff2344ddb5c5cf7d121cd17d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Wed, 22 Mar 2023 17:51:00 +0300 Subject: [PATCH 463/647] =?UTF-8?q?-=20=D0=A2=D0=B5=D1=81=D1=82=20=D0=BD?= =?UTF-8?q?=D0=B0=2010=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/Integration/OperatingTimingTest/OperatingTimingTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Integration/OperatingTimingTest/OperatingTimingTest.php b/tests/Integration/OperatingTimingTest/OperatingTimingTest.php index 2a676b40..1e35c665 100644 --- a/tests/Integration/OperatingTimingTest/OperatingTimingTest.php +++ b/tests/Integration/OperatingTimingTest/OperatingTimingTest.php @@ -29,7 +29,7 @@ class OperatingTimingTest extends TestCase public function testOperatingTiming(): void { $masContacts = []; - for ($i = 0; $i < 5; $i++) { + for ($i = 0; $i < 10000; $i++) { $phoneNumberWork = sprintf('+7%s', time()); $phoneNumberHome = sprintf('%s', microtime()); $phoneNumberHome = implode("-", str_split(substr($phoneNumberHome, 2, -13), 2)); From f3699426d2c75aebd80a766cf508da2e411dab5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Thu, 23 Mar 2023 17:43:13 +0300 Subject: [PATCH 464/647] =?UTF-8?q?-=20=D0=98=D0=B7=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=20=D1=82=D0=B5=D1=81=D1=82=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D0=B3=D0=B5=D0=BD=D0=B5=D1=80=D0=B0=D1=86=D0=B8=D0=B8=20=D0=B4?= =?UTF-8?q?=D0=B0=D0=BD=D0=BD=D1=8B=D1=85=20!!!=20-=20=D0=94=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B0=20=D1=87=D0=B0=D1=81=D1=82?= =?UTF-8?q?=D1=8C=20=D0=BA=D0=BE=D0=B4=D0=B0=20=D0=B2=20=D1=82=D0=B5=D1=81?= =?UTF-8?q?=D1=82=D0=B5=20=D0=B4=D0=BB=D1=8F=20=D0=BF=D0=BE=D0=B8=D1=81?= =?UTF-8?q?=D0=BA=D0=B0=20=D1=81=D0=BE=D0=B7=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B?= =?UTF-8?q?=D1=85=20=D0=BA=D0=BE=D0=BD=D1=82=D0=B0=D0=BA=D1=82=D0=BE=D0=B2?= =?UTF-8?q?=20=D1=81=20=D0=BF=D0=BE=D0=BC=D0=BE=D1=89=D1=8C=D1=8E=20=D0=B1?= =?UTF-8?q?=D0=B0=D1=82=D1=87=D0=B0=20=D0=B8=20=D0=BC=D0=B5=D1=82=D0=BE?= =?UTF-8?q?=D0=B4=D0=B0=20list.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../OperatingTimingTest.php | 26 ++++++++++++------- .../CRM/Contacts/GenerateContactsCommand.php | 5 ++-- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/tests/Integration/OperatingTimingTest/OperatingTimingTest.php b/tests/Integration/OperatingTimingTest/OperatingTimingTest.php index 1e35c665..88c1dc06 100644 --- a/tests/Integration/OperatingTimingTest/OperatingTimingTest.php +++ b/tests/Integration/OperatingTimingTest/OperatingTimingTest.php @@ -5,10 +5,8 @@ namespace Bitrix24\SDK\Tests\Integration\OperatingTimingTest; use Bitrix24\SDK\Core\Batch; -use Bitrix24\SDK\Core\Exceptions\BaseException; -use Bitrix24\SDK\Core\Exceptions\TransportException; + use Bitrix24\SDK\Services\CRM\Contact\Service\Contact; -use Bitrix24\SDK\Services\ServiceBuilder; use Bitrix24\SDK\Tests\Integration\Fabric; use PHPUnit\Framework\TestCase; @@ -28,7 +26,7 @@ class OperatingTimingTest extends TestCase */ public function testOperatingTiming(): void { - $masContacts = []; + /* $masContacts = []; for ($i = 0; $i < 10000; $i++) { $phoneNumberWork = sprintf('+7%s', time()); $phoneNumberHome = sprintf('%s', microtime()); @@ -50,16 +48,24 @@ public function testOperatingTiming(): void ] ]; - } - $contactsIdList = []; + }*/ + /* $contactsIdList = []; foreach ($this->batch->addEntityItems('crm.contact.add', $masContacts) as $addContactResult) { $contactsIdList[] = $addContactResult->getResult(); + }*/ + $cnt = 0; + foreach ($this->contactService->batch->list([], ['>ID' => '103575'], ['ID','PHONE'], 5) as $contactList) { + $cnt++; + $contactListId[] = $contactList->ID; + $contactListPhone[] = $contactList->PHONE; + } - foreach ($contactsIdList as $contactId) { - $contactPhoneId = $this->contactService->get($contactId[0])->contact()->PHONE[0]['ID']; - $contactUpdate = $this->contactService->update((int)$contactId[0],['PHONE' => [['ID' => $contactPhoneId, 'VALUE' => ""]]],[ "REGISTER_SONET_EVENT" => "Y"]); + foreach ($contactListId as $contactId) { + $contactPhoneId = $this->contactService->get($contactId)->contact()->PHONE[0]['ID']; + $contactUpdate = $this->contactService->update((int)$contactId,['PHONE' => [['ID' => $contactPhoneId, 'VALUE' => ""]]],[ "REGISTER_SONET_EVENT" => "Y"]); } - $this->assertCount(5, $contactsIdList); + self::assertGreaterThanOrEqual(5, $contactListId); + } public function setUp(): void diff --git a/tools/DemoDataGenerators/CRM/Contacts/GenerateContactsCommand.php b/tools/DemoDataGenerators/CRM/Contacts/GenerateContactsCommand.php index baaa96b4..c983863f 100644 --- a/tools/DemoDataGenerators/CRM/Contacts/GenerateContactsCommand.php +++ b/tools/DemoDataGenerators/CRM/Contacts/GenerateContactsCommand.php @@ -199,10 +199,11 @@ protected function generateContacts(int $contactsCount): array 'SECOND_NAME' => sprintf('second_%s', $i), 'PHONE' => [ ['VALUE' => sprintf('+7978%s', random_int(1000000, 9999999)), 'VALUE_TYPE' => 'MOBILE'], + ['VALUE' => implode("-", str_split(substr( sprintf('%s', microtime()), 2, -13), 2))], ], - 'EMAIL' => [ + /* 'EMAIL' => [ ['VALUE' => sprintf('test-%s@gmail.com', random_int(1000000, 9999999)), 'VALUE_TYPE' => 'WORK'], - ], + ],*/ ]; } From fe616ece0c5eb4282ef1d816d30a6f7128d9d28f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Thu, 23 Mar 2023 17:43:13 +0300 Subject: [PATCH 465/647] =?UTF-8?q?-=20=D0=93=D0=B5=D0=BD=D0=B5=D1=80?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D1=8F=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85?= =?UTF-8?q?=20=D0=BF=D0=BE=D0=B4=D0=BA=D1=80=D1=83=D1=87=D0=B5=D0=BD=D0=B0?= =?UTF-8?q?=20=D0=B4=D0=BB=D1=8F=20=D0=BD=D0=B0=D1=88=D0=B5=D0=B3=D0=BE=20?= =?UTF-8?q?=D1=82=D0=B5=D1=81=D1=82=D0=B0!=20-=20=D0=94=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B0=20=D1=87=D0=B0=D1=81=D1=82=D1=8C?= =?UTF-8?q?=20=D0=BA=D0=BE=D0=B4=D0=B0=20=D0=B2=20=D1=82=D0=B5=D1=81=D1=82?= =?UTF-8?q?=D0=B5=20=D0=B4=D0=BB=D1=8F=20=D0=BF=D0=BE=D0=B8=D1=81=D0=BA?= =?UTF-8?q?=D0=B0=20=D1=81=D0=BE=D0=B7=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85?= =?UTF-8?q?=20=D0=BA=D0=BE=D0=BD=D1=82=D0=B0=D0=BA=D1=82=D0=BE=D0=B2=20?= =?UTF-8?q?=D1=81=20=D0=BF=D0=BE=D0=BC=D0=BE=D1=89=D1=8C=D1=8E=20=D0=B1?= =?UTF-8?q?=D0=B0=D1=82=D1=87=D0=B0=20=D0=B8=20=D0=BC=D0=B5=D1=82=D0=BE?= =?UTF-8?q?=D0=B4=D0=B0=20list.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../OperatingTimingTest.php | 26 ++++++++++++------- .../CRM/Contacts/GenerateContactsCommand.php | 5 ++-- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/tests/Integration/OperatingTimingTest/OperatingTimingTest.php b/tests/Integration/OperatingTimingTest/OperatingTimingTest.php index 1e35c665..88c1dc06 100644 --- a/tests/Integration/OperatingTimingTest/OperatingTimingTest.php +++ b/tests/Integration/OperatingTimingTest/OperatingTimingTest.php @@ -5,10 +5,8 @@ namespace Bitrix24\SDK\Tests\Integration\OperatingTimingTest; use Bitrix24\SDK\Core\Batch; -use Bitrix24\SDK\Core\Exceptions\BaseException; -use Bitrix24\SDK\Core\Exceptions\TransportException; + use Bitrix24\SDK\Services\CRM\Contact\Service\Contact; -use Bitrix24\SDK\Services\ServiceBuilder; use Bitrix24\SDK\Tests\Integration\Fabric; use PHPUnit\Framework\TestCase; @@ -28,7 +26,7 @@ class OperatingTimingTest extends TestCase */ public function testOperatingTiming(): void { - $masContacts = []; + /* $masContacts = []; for ($i = 0; $i < 10000; $i++) { $phoneNumberWork = sprintf('+7%s', time()); $phoneNumberHome = sprintf('%s', microtime()); @@ -50,16 +48,24 @@ public function testOperatingTiming(): void ] ]; - } - $contactsIdList = []; + }*/ + /* $contactsIdList = []; foreach ($this->batch->addEntityItems('crm.contact.add', $masContacts) as $addContactResult) { $contactsIdList[] = $addContactResult->getResult(); + }*/ + $cnt = 0; + foreach ($this->contactService->batch->list([], ['>ID' => '103575'], ['ID','PHONE'], 5) as $contactList) { + $cnt++; + $contactListId[] = $contactList->ID; + $contactListPhone[] = $contactList->PHONE; + } - foreach ($contactsIdList as $contactId) { - $contactPhoneId = $this->contactService->get($contactId[0])->contact()->PHONE[0]['ID']; - $contactUpdate = $this->contactService->update((int)$contactId[0],['PHONE' => [['ID' => $contactPhoneId, 'VALUE' => ""]]],[ "REGISTER_SONET_EVENT" => "Y"]); + foreach ($contactListId as $contactId) { + $contactPhoneId = $this->contactService->get($contactId)->contact()->PHONE[0]['ID']; + $contactUpdate = $this->contactService->update((int)$contactId,['PHONE' => [['ID' => $contactPhoneId, 'VALUE' => ""]]],[ "REGISTER_SONET_EVENT" => "Y"]); } - $this->assertCount(5, $contactsIdList); + self::assertGreaterThanOrEqual(5, $contactListId); + } public function setUp(): void diff --git a/tools/DemoDataGenerators/CRM/Contacts/GenerateContactsCommand.php b/tools/DemoDataGenerators/CRM/Contacts/GenerateContactsCommand.php index baaa96b4..c983863f 100644 --- a/tools/DemoDataGenerators/CRM/Contacts/GenerateContactsCommand.php +++ b/tools/DemoDataGenerators/CRM/Contacts/GenerateContactsCommand.php @@ -199,10 +199,11 @@ protected function generateContacts(int $contactsCount): array 'SECOND_NAME' => sprintf('second_%s', $i), 'PHONE' => [ ['VALUE' => sprintf('+7978%s', random_int(1000000, 9999999)), 'VALUE_TYPE' => 'MOBILE'], + ['VALUE' => implode("-", str_split(substr( sprintf('%s', microtime()), 2, -13), 2))], ], - 'EMAIL' => [ + /* 'EMAIL' => [ ['VALUE' => sprintf('test-%s@gmail.com', random_int(1000000, 9999999)), 'VALUE_TYPE' => 'WORK'], - ], + ],*/ ]; } From eacb965c50871e74e478439f8039a138042f8121 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Thu, 23 Mar 2023 20:04:35 +0300 Subject: [PATCH 466/647] =?UTF-8?q?-=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=20update=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20batch=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=B0=D1=8E=D1=89=D0=B5=D0=B3=D0=BE=20=D1=81=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=BD=D1=82=D0=B0=D0=BA=D1=82=D0=B0=D0=BC=D0=B8.=20-=20=D0=92?= =?UTF-8?q?=20=D1=82=D0=B5=D1=81=D1=82=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B0=20=D1=87=D0=B0=D1=81=D1=82=D1=8C=20?= =?UTF-8?q?=D1=81=20update=20=D0=B8=D1=81=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7?= =?UTF-8?q?=D1=83=D1=8E=D1=89=D0=B0=D1=8F=20=D0=B1=D0=B0=D1=82=D1=87.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Services/CRM/Contact/Service/Batch.php | 22 +++++++++ .../OperatingTimingTest.php | 47 +++++-------------- 2 files changed, 34 insertions(+), 35 deletions(-) diff --git a/src/Services/CRM/Contact/Service/Batch.php b/src/Services/CRM/Contact/Service/Batch.php index 696720a2..02cfec3f 100644 --- a/src/Services/CRM/Contact/Service/Batch.php +++ b/src/Services/CRM/Contact/Service/Batch.php @@ -7,6 +7,7 @@ use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Result\AddedItemBatchResult; use Bitrix24\SDK\Core\Result\DeletedItemBatchResult; +use Bitrix24\SDK\Core\Result\UpdatedItemBatchResult; use Bitrix24\SDK\Services\AbstractBatchService; use Bitrix24\SDK\Services\CRM\Contact\Result\ContactItemResult; use Generator; @@ -224,4 +225,25 @@ public function delete(array $contactId): Generator yield $key => new DeletedItemBatchResult($item); } } + + /** + * Update contact + * + * Update elements in array with structure + * element_id => [ // deal id + * 'fields' => [], // deal fields to update + * 'params' => [] + * ] + * + * @param array $entityItems + * + * @return \Generator + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function update(array $entityItems): Generator + { + foreach ($this->batch->updateEntityItems('crm.contact.update', $entityItems) as $key => $item) { + yield $key => new UpdatedItemBatchResult($item); + } + } } \ No newline at end of file diff --git a/tests/Integration/OperatingTimingTest/OperatingTimingTest.php b/tests/Integration/OperatingTimingTest/OperatingTimingTest.php index 88c1dc06..fb928de6 100644 --- a/tests/Integration/OperatingTimingTest/OperatingTimingTest.php +++ b/tests/Integration/OperatingTimingTest/OperatingTimingTest.php @@ -3,9 +3,7 @@ declare(strict_types=1); namespace Bitrix24\SDK\Tests\Integration\OperatingTimingTest; - use Bitrix24\SDK\Core\Batch; - use Bitrix24\SDK\Services\CRM\Contact\Service\Contact; use Bitrix24\SDK\Tests\Integration\Fabric; use PHPUnit\Framework\TestCase; @@ -18,7 +16,7 @@ class OperatingTimingTest extends TestCase { protected Contact $contactService; - private Batch $batch; + protected Batch $batch; /** * @throws \Bitrix24\SDK\Core\Exceptions\TransportException @@ -26,44 +24,23 @@ class OperatingTimingTest extends TestCase */ public function testOperatingTiming(): void { - /* $masContacts = []; - for ($i = 0; $i < 10000; $i++) { - $phoneNumberWork = sprintf('+7%s', time()); - $phoneNumberHome = sprintf('%s', microtime()); - $phoneNumberHome = implode("-", str_split(substr($phoneNumberHome, 2, -13), 2)); - $masContacts[] = [ - 'fields' => [ - 'NAME' => sprintf('first_%s', time()), - 'SECOND' => sprintf('second_%s', time()), - 'PHONE' => [ - [ - 'VALUE' => $phoneNumberWork, - 'VALUE_TYPE' => 'WORK' - ], - [ - 'VALUE' => $phoneNumberHome, - 'VALUE_TYPE' => 'HOME' - ] - ], - ] - ]; - }*/ - /* $contactsIdList = []; - foreach ($this->batch->addEntityItems('crm.contact.add', $masContacts) as $addContactResult) { - $contactsIdList[] = $addContactResult->getResult(); - }*/ $cnt = 0; - foreach ($this->contactService->batch->list([], ['>ID' => '103575'], ['ID','PHONE'], 5) as $contactList) { + $contactsToUpdate = []; + foreach ($this->contactService->batch->list([], ['>ID' => '103595'], ['ID','PHONE'], 30000) as $contactList) { $cnt++; + $contactsToUpdate[$contactList->ID] = [ + 'fields' => [ + 'PHONE' => [['ID' =>$contactList->PHONE[0]['ID']]] + ], + 'params' => [], + ]; $contactListId[] = $contactList->ID; - $contactListPhone[] = $contactList->PHONE; - } - foreach ($contactListId as $contactId) { - $contactPhoneId = $this->contactService->get($contactId)->contact()->PHONE[0]['ID']; - $contactUpdate = $this->contactService->update((int)$contactId,['PHONE' => [['ID' => $contactPhoneId, 'VALUE' => ""]]],[ "REGISTER_SONET_EVENT" => "Y"]); + foreach ($this->contactService->batch->update($contactsToUpdate) as $dealUpdateResult) { + $this->assertTrue($dealUpdateResult->isSuccess()); } + self::assertGreaterThanOrEqual(5, $contactListId); } From 61b2d364238172947aa5b687af2003a395f5112a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Sat, 25 Mar 2023 01:00:25 +0300 Subject: [PATCH 467/647] =?UTF-8?q?-=20=D0=98=D1=81=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=BE=D0=BF=D0=B5=D1=87=D0=B0?= =?UTF-8?q?=D1=82=D0=BA=D0=B0=20=D0=B2=20=D0=BE=D0=BF=D0=B8=D1=81=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D0=B8=20=D0=BA=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4?= =?UTF-8?q?=D1=83.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Services/CRM/Contact/Service/Batch.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Services/CRM/Contact/Service/Batch.php b/src/Services/CRM/Contact/Service/Batch.php index 02cfec3f..e75165d3 100644 --- a/src/Services/CRM/Contact/Service/Batch.php +++ b/src/Services/CRM/Contact/Service/Batch.php @@ -230,8 +230,8 @@ public function delete(array $contactId): Generator * Update contact * * Update elements in array with structure - * element_id => [ // deal id - * 'fields' => [], // deal fields to update + * element_id => [ // contact id + * 'fields' => [], // contact fields to update * 'params' => [] * ] * From e3ffe75cf59202b14cd974d057faf4da10b00a9c Mon Sep 17 00:00:00 2001 From: mesilov Date: Tue, 28 Mar 2023 01:15:56 +0400 Subject: [PATCH 468/647] add batch update for contact Signed-off-by: mesilov --- CHANGELOG.md | 97 +++++++---- src/Core/Batch.php | 162 +++++++++--------- src/Services/CRM/Contact/Service/Batch.php | 23 +++ .../CRM/Contact/Service/ContactBatchTest.php | 122 +++++++++++++ .../CRM/Contact/Service/ContactTest.php | 29 ---- 5 files changed, 292 insertions(+), 141 deletions(-) create mode 100644 tests/Integration/Services/CRM/Contact/Service/ContactBatchTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 34531975..16659f2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,23 +1,26 @@ # bitrix24-php-sdk change log -## 2.0-beta.1 — 25.02.2023 +## 2.0-beta.1 — 25.03.2023 ### Added * add `Symfony\Component\Uid\Uuid` requirements -* add contracts for bitrix24 applications based on bitrix24-php-sdk - `Bitrix24\SDK\Application\Contracts`, now added `Bitrix24Account` +* add contracts for bitrix24 applications based on bitrix24-php-sdk - `Bitrix24\SDK\Application\Contracts`, now + added `Bitrix24Account` * add [service builder factory](https://github.com/mesilov/bitrix24-php-sdk/issues/328) * add method `Bitrix24\SDK\Core\Credentials\Scope::initFromString` * add method `Bitrix24\SDK\Application\ApplicationStatus::initFromString` * ❗️add php 8.2 support * add system CRM multi-field type `Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\Phone` -* add scope `user`,`user_basic`,`user_brief`,`user.userfield` and services [add scope user support](https://github.com/mesilov/bitrix24-php-sdk/issues/339) - * `Bitrix24\SDK\Services\User\Service\User::fields` - get user fields - * `Bitrix24\SDK\Services\User\Service\User::current` - get current user - * `Bitrix24\SDK\Services\User\Service\User::add` - add user - * `Bitrix24\SDK\Services\User\Service\User::get` - get user - * `Bitrix24\SDK\Services\User\Service\User::update` - update user - * `Bitrix24\SDK\Services\User\Service\User::search` - search users +* add scope `user`,`user_basic`,`user_brief`,`user.userfield` and + services [add scope user support](https://github.com/mesilov/bitrix24-php-sdk/issues/339) + * `Bitrix24\SDK\Services\User\Service\User::fields` - get user fields + * `Bitrix24\SDK\Services\User\Service\User::current` - get current user + * `Bitrix24\SDK\Services\User\Service\User::add` - add user + * `Bitrix24\SDK\Services\User\Service\User::get` - get user + * `Bitrix24\SDK\Services\User\Service\User::update` - update user + * `Bitrix24\SDK\Services\User\Service\User::search` - search users +* add method `\Bitrix24\SDK\Services\CRM\Contact\Service\Batch::update()` for batch update contacts ### Changed @@ -43,6 +46,7 @@ * fix errors in `ShowFieldsDescriptionCommand` metadata reader CLI command ### etc + * move CLI entry point to `bin/console` ## 2.0-alpha.7 — 8.08.2022 @@ -50,34 +54,46 @@ ### Added * add new scope `Telephony` and services [add Telephony support](https://github.com/mesilov/bitrix24-php-sdk/issues/291) -* add new scope `UserConsent` and services [add UserConsent support](https://github.com/mesilov/bitrix24-php-sdk/issues/285) -* add new scope `Placements` and services [add Placements support](https://github.com/mesilov/bitrix24-php-sdk/issues/274) -* add new scope `IMOpenLines` and services [add IM Open Lines support](https://github.com/mesilov/bitrix24-php-sdk/issues/302) -* add in scope `CRM` new service `Leads` in scope «CRM» [add Leads support](https://github.com/mesilov/bitrix24-php-sdk/issues/282) -* add in scope `CRM` new service `Activity` in scope «CRM» [add Activity support](https://github.com/mesilov/bitrix24-php-sdk/issues/283) +* add new scope `UserConsent` and + services [add UserConsent support](https://github.com/mesilov/bitrix24-php-sdk/issues/285) +* add new scope `Placements` and + services [add Placements support](https://github.com/mesilov/bitrix24-php-sdk/issues/274) +* add new scope `IMOpenLines` and + services [add IM Open Lines support](https://github.com/mesilov/bitrix24-php-sdk/issues/302) +* add in scope `CRM` new service `Leads` in scope + «CRM» [add Leads support](https://github.com/mesilov/bitrix24-php-sdk/issues/282) +* add in scope `CRM` new service `Activity` in scope + «CRM» [add Activity support](https://github.com/mesilov/bitrix24-php-sdk/issues/283) * add in scope `CRM` for entity Deal method `Services\CRM\Deal\Service\Batch::update` batch update deals * add in scope `CRM` for entity Contact method `Services\CRM\Contact\Service\Batch::delete` batch delete contacts -* add in scope `CRM` [read models](https://github.com/mesilov/bitrix24-php-sdk/issues/300) for activity `Services\CRM\Activity\ReadModel` +* add in scope `CRM` [read models](https://github.com/mesilov/bitrix24-php-sdk/issues/300) for + activity `Services\CRM\Activity\ReadModel` for activity types: `EmailFetcher`, `OpenLineFetcher`, `VoximplantFetcher`, `WebFormFetcher` -* add in scope «Main» new service `Events` [add incoming events support](https://github.com/mesilov/bitrix24-php-sdk/issues/296) +* add in scope «Main» new + service `Events` [add incoming events support](https://github.com/mesilov/bitrix24-php-sdk/issues/296) * add support Application level events: `ONAPPINSTALL` and `ONAPPUNINSTALL` [add incoming events support](https://github.com/mesilov/bitrix24-php-sdk/issues/296) * add support Application level event: `PortalDomainUrlChangedEvent` -* add method `Core\Batch::updateEntityItems` for [update items in batch mode](https://github.com/mesilov/bitrix24-php-sdk/issues/268) and +* add method `Core\Batch::updateEntityItems` + for [update items in batch mode](https://github.com/mesilov/bitrix24-php-sdk/issues/268) and integration test * add method to interface `Core\Contracts\BatchInterface::updateEntityItems` for update items in batch mode * add in scope `Placements` service `Placement\Service\UserFieldType` for work with user fields embedding -* add in scope `Telephony` add events: `OnExternalCallBackStart`, `OnExternalCallStart`, `OnVoximplantCallEnd`, `OnVoximplantCallEnd` - , `OnVoximplantCallInit`, `OnVoximplantCallStart` see [add telephony events](https://github.com/mesilov/bitrix24-php-sdk/issues/304) +* add in scope `Telephony` add + events: `OnExternalCallBackStart`, `OnExternalCallStart`, `OnVoximplantCallEnd`, `OnVoximplantCallEnd` + , `OnVoximplantCallInit`, `OnVoximplantCallStart` + see [add telephony events](https://github.com/mesilov/bitrix24-php-sdk/issues/304) * add `ApplicationStatus` with application status codes description * add fabric method `AccessToken::initFromPlacementRequest` when application init form placement request * add fabric method `ApplicationProfile::initFromArray` when application profile stored in ENV-variables * add `Bitrix24\SDK\Application\Requests\Placement\PlacementRequest` for application data from placements * add fabric method `Credentials::initFromPlacementRequest` when application init form placement request * add method `Services\Main\Service::getServerTime` returns current server time in the format YYYY-MM-DDThh:mm:ss±hh:mm. -* add method `Services\Main\Service::getCurrentUserProfile` return basic Information about the current user without any scopes +* add method `Services\Main\Service::getCurrentUserProfile` return basic Information about the current user without any + scopes * add method `Services\Main\Service::getAccessName` returns access permission names. -* add method `Services\Main\Service::checkUserAccess` Checks if the current user has at least one permission of those specified by the +* add method `Services\Main\Service::checkUserAccess` Checks if the current user has at least one permission of those + specified by the ACCESS parameter. * add method `Services\Main\Service::getMethodAffordability` Method returns 2 parameters - isExisting and isAvailable * add money type support by [phpmoney](https://github.com/moneyphp/money) @@ -85,16 +101,20 @@ ### Changed -* update scope list [расширить и актуализировать доступные скоупы](https://github.com/mesilov/bitrix24-php-sdk/issues/280) +* update scope + list [расширить и актуализировать доступные скоупы](https://github.com/mesilov/bitrix24-php-sdk/issues/280) * bump `symfony/*` to `6.*` version requirement. * method `Services\Main\Service::getAvailableMethods` marks as deprecated * method `Services\Main\Service::getAllMethods` marks as deprecated * method `Services\Main\Service::getMethodsByScope` marks as deprecated * ❗️fabric methods `Bitrix24\SDK\Core\Credentials` - renamed and now are [consistent](https://github.com/mesilov/bitrix24-php-sdk/issues/303): `createFromWebhook`, `createFromOAuth` + renamed and now + are [consistent](https://github.com/mesilov/bitrix24-php-sdk/issues/303): `createFromWebhook`, `createFromOAuth` , `createFromPlacementRequest` -* ❗️deleted [unused class](https://github.com/mesilov/bitrix24-php-sdk/issues/303) `Bitrix24\SDK\Core\Response\DTO\ResponseDataCollection` -* ❗️deleted [redundant class](https://github.com/mesilov/bitrix24-php-sdk/issues/303) `Bitrix24\SDK\Core\Response\DTO\Result` +* +❗️deleted [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` @@ -102,7 +122,8 @@ * add bugfix for batch method for reverse order queries * fix type compatible errors for `Core\Result\AbstractItem` -* fix error in `NetworkTimingParser`, [error in NetworkTimingsErrorInfo](https://github.com/mesilov/bitrix24-php-sdk/issues/277) +* fix error + in `NetworkTimingParser`, [error in NetworkTimingsErrorInfo](https://github.com/mesilov/bitrix24-php-sdk/issues/277) * fix error in `RenewedAccessToken` DTO, remove `Scope` enum [UnknownScopeCodeException - in refresh token response](https://github.com/mesilov/bitrix24-php-sdk/issues/295) @@ -116,18 +137,22 @@ * add «fast» batch-query without counting elements in result recordset [Добавить поддержку выгрузки большого количества данных без подсчёта элементов -1](https://github.com/mesilov/bitrix24-php-sdk/issues/248) -* add `Credentials` in CoreBuilder [set credentials from core builder](https://github.com/mesilov/bitrix24-php-sdk/pull/246) +* add `Credentials` in + CoreBuilder [set credentials from core builder](https://github.com/mesilov/bitrix24-php-sdk/pull/246) * add method `Core\Batch::deleteEntityItems` for delete items in batch mode and integration test * add integration test for read strategy `FilterWithBatchWithoutCountOrderTest` * add type check in method `Core\Batch::deleteEntityItems` - only integer id allowed * add interface `Core\Contracts\DeletedItemResultInterface` * add in scope «CRM» `Services\CRM\Deal\Service\Batch::delete` batch delete deals * add `symfony/stopwatch` component for integration tests -* add `/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser` for parse `curl_info` network data structures for debug logs +* add `/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser` for parse `curl_info` network data structures for + debug logs in `Bitrix24\SDK\Core\Response::__destruct()` -* add `/Infrastructure/HttpClient/TransportLayer/ResponseInfoParser` for parse `bitrix24_rest_api` timing info for debug logs +* add `/Infrastructure/HttpClient/TransportLayer/ResponseInfoParser` for parse `bitrix24_rest_api` timing info for debug + logs in `Bitrix24\SDK\Core\Response::__destruct()` -* add `Bitrix24\SDK\Core\BulkItemsReader` for data-intensive applications for bulk export data from Bitrix24, read strategies located in +* add `Bitrix24\SDK\Core\BulkItemsReader` for data-intensive applications for bulk export data from Bitrix24, read + strategies located in folder `ReadStrategies`, in services read model **must** use most effective read strategy. * add integration tests in GitHub Actions pipeline 🎉, now integration tests run on push on `dev-branch` * add incoming webhook for run integration tests `vendor-check.yml` from vendor CI\CD pipeline @@ -138,7 +163,8 @@ * switch `symfony/http-client-contracts` to `^2.5` version requirement. * switch `symfony/event-dispatcher` to `5.4.*` version requirement. * switch `ramsey/uuid` to `^4.2.3` version requirement. -* switch `psr/log` to `^1.1.4 || ^2.0 || ^3.0` [version requirement](https://github.com/mesilov/bitrix24-php-sdk/issues/245). +* switch `psr/log` + to `^1.1.4 || ^2.0 || ^3.0` [version requirement](https://github.com/mesilov/bitrix24-php-sdk/issues/245). ## 2.0-alpha.5 – 28.11.2021 @@ -161,7 +187,8 @@ ### Changed -* update type definition for `ContactItemResult`, now return types will be cast to real types: DateTimeInterface, int, boolean etc +* update type definition for `ContactItemResult`, now return types will be cast to real types: DateTimeInterface, int, + boolean etc ## 2.0-alpha.4 – 25.11.2021 @@ -283,10 +310,12 @@ branch version 1.x – bugfix and security releases only ## 0.5.0 (4.09.2016) -* add class `Bitrix24\CRM\Quote` see pr [Added support for Quote API calls](https://github.com/mesilov/bitrix24-php-sdk/pull/53/) +* add class `Bitrix24\CRM\Quote` see + pr [Added support for Quote API calls](https://github.com/mesilov/bitrix24-php-sdk/pull/53/) * add support http status 301 moved permanently in class `Bitrix24` see issue [301 Moved Permanently #49](https://github.com/mesilov/bitrix24-php-sdk/issues/49) -* fixed bug in class `Bitrix24` see pr [Issue in the isAccessTokenExpire method](https://github.com/mesilov/bitrix24-php-sdk/pull/54) +* fixed bug in class `Bitrix24` see + pr [Issue in the isAccessTokenExpire method](https://github.com/mesilov/bitrix24-php-sdk/pull/54) ## 0.4.1 (4.08.2016) diff --git a/src/Core/Batch.php b/src/Core/Batch.php index d4123b87..c28bd28f 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -34,7 +34,7 @@ class Batch implements BatchOperationsInterface /** * Batch constructor. * - * @param CoreInterface $core + * @param CoreInterface $core * @param LoggerInterface $log */ public function __construct(CoreInterface $core, LoggerInterface $log) @@ -62,7 +62,7 @@ protected function clearCommands(): void /** * Add entity items with batch call * - * @param string $apiMethod + * @param string $apiMethod * @param array $entityItems * * @return Generator|ResponseData[] @@ -73,7 +73,7 @@ public function addEntityItems(string $apiMethod, array $entityItems): Generator $this->logger->debug( 'addEntityItems.start', [ - 'apiMethod' => $apiMethod, + 'apiMethod' => $apiMethod, 'entityItems' => $entityItems, ] ); @@ -105,7 +105,7 @@ public function addEntityItems(string $apiMethod, array $entityItems): Generator /** * Delete entity items with batch call * - * @param string $apiMethod + * @param string $apiMethod * @param array $entityItemId * * @return Generator|ResponseData[] @@ -116,7 +116,7 @@ public function deleteEntityItems(string $apiMethod, array $entityItemId): Gener $this->logger->debug( 'deleteEntityItems.start', [ - 'apiMethod' => $apiMethod, + 'apiMethod' => $apiMethod, 'entityItems' => $entityItemId, ] ); @@ -173,7 +173,7 @@ public function deleteEntityItems(string $apiMethod, array $entityItemId): Gener * 'params' => [] // optional fields * ] * - * @param string $apiMethod + * @param string $apiMethod * @param array> $entityItems * * @return Generator|ResponseData[] @@ -184,7 +184,7 @@ public function updateEntityItems(string $apiMethod, array $entityItems): Genera $this->logger->debug( 'updateEntityItems.start', [ - 'apiMethod' => $apiMethod, + 'apiMethod' => $apiMethod, 'entityItems' => $entityItems, ] ); @@ -207,11 +207,14 @@ public function updateEntityItems(string $apiMethod, array $entityItems): Genera ); } - $this->registerCommand($apiMethod, [ - 'id' => $entityItemId, - 'fields' => $entityItem['fields'], - 'params' => $entityItem['params'], - ]); + $cmdArguments = [ + 'id' => $entityItemId, + 'fields' => $entityItem['fields'] + ]; + if (array_key_exists('params', $entityItem)) { + $cmdArguments['params'] = $entityItem['params']; + } + $this->registerCommand($apiMethod, $cmdArguments); } foreach ($this->getTraversable(true) as $cnt => $updatedItemResult) { @@ -244,24 +247,25 @@ public function updateEntityItems(string $apiMethod, array $entityItems): Genera /** * Register api command to command collection for batch calls * - * @param string $apiMethod + * @param string $apiMethod * @param array $parameters - * @param string|null $commandName - * @param callable|null $callback not implemented + * @param string|null $commandName + * @param callable|null $callback not implemented * * @throws \Exception */ protected function registerCommand( - string $apiMethod, - array $parameters = [], - ?string $commandName = null, + string $apiMethod, + array $parameters = [], + ?string $commandName = null, callable $callback = null - ): void { + ): void + { $this->logger->debug( 'registerCommand.start', [ - 'apiMethod' => $apiMethod, - 'parameters' => $parameters, + 'apiMethod' => $apiMethod, + 'parameters' => $parameters, 'commandName' => $commandName, ] ); @@ -317,11 +321,11 @@ protected function getReverseOrder(array $order): array /** * Get traversable list without count elements * - * @param string $apiMethod + * @param string $apiMethod * @param array $order - * @param array $filter - * @param array $select - * @param int|null $limit + * @param array $filter + * @param array $select + * @param int|null $limit * * @return \Generator * @throws \Bitrix24\SDK\Core\Exceptions\BaseException @@ -333,19 +337,20 @@ protected function getReverseOrder(array $order): array */ public function getTraversableList( string $apiMethod, - array $order, - array $filter, - array $select, - ?int $limit = null - ): Generator { + array $order, + array $filter, + array $select, + ?int $limit = null + ): Generator + { $this->logger->debug( 'getTraversableList.start', [ 'apiMethod' => $apiMethod, - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'limit' => $limit, + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'limit' => $limit, ] ); @@ -379,10 +384,10 @@ public function getTraversableList( $firstResultPage = $this->core->call( $apiMethod, [ - 'order' => $order, + 'order' => $order, 'filter' => $filter, 'select' => $select, - 'start' => 0, + 'start' => 0, ] ); $totalElementsCount = $firstResultPage->getResponseData()->getPagination()->getTotal(); @@ -425,10 +430,10 @@ public function getTraversableList( $lastResultPage = $this->core->call( $apiMethod, [ - 'order' => $this->getReverseOrder($order), + 'order' => $this->getReverseOrder($order), 'filter' => $filter, 'select' => $select, - 'start' => 0, + 'start' => 0, ] ); $lastElementId = (int)$lastResultPage->getResponseData()->getResult()[0]['ID']; @@ -440,7 +445,7 @@ public function getTraversableList( } $this->logger->debug('getTraversableList.lastElementsId', [ 'lastElementIdInFirstPage' => $lastElementIdInFirstPage, - 'lastElementId' => $lastElementId, + 'lastElementId' => $lastElementId, ]); // register commands with updated filter @@ -448,9 +453,9 @@ public function getTraversableList( $lastElementIdInFirstPage++; for ($startId = $lastElementIdInFirstPage; $startId <= $lastElementId; $startId += self::MAX_ELEMENTS_IN_PAGE) { $this->logger->debug('registerCommand.item', [ - 'startId' => $startId, + 'startId' => $startId, 'lastElementId' => $lastElementId, - 'delta' => $lastElementId - $startId, + 'delta' => $lastElementId - $startId, ]); $delta = $lastElementId - $startId; @@ -468,10 +473,10 @@ public function getTraversableList( $this->registerCommand( $apiMethod, [ - 'order' => [], + 'order' => [], 'filter' => $this->updateFilterForBatch($startId, $lastElementIdInPage, $isLastPage, $filter), 'select' => $select, - 'start' => -1, + 'start' => -1, ] ); } @@ -492,8 +497,8 @@ public function getTraversableList( 'getTraversableList.batchResultItem', [ 'batchCommandItemNumber' => $queryCnt, - 'nextItem' => $queryResultData->getPagination()->getNextItem(), - 'durationTime' => $queryResultData->getTime()->getDuration(), + 'nextItem' => $queryResultData->getPagination()->getNextItem(), + 'durationTime' => $queryResultData->getTime()->getDuration(), ] ); // iterate items in batch query result @@ -509,9 +514,9 @@ public function getTraversableList( } /** - * @param int $startElementId - * @param int $lastElementId - * @param bool $isLastPage + * @param int $startElementId + * @param int $lastElementId + * @param bool $isLastPage * @param array $oldFilter * * @return array @@ -520,15 +525,15 @@ protected function updateFilterForBatch(int $startElementId, int $lastElementId, { $this->logger->debug('updateFilterForBatch.start', [ 'startElementId' => $startElementId, - 'lastElementId' => $lastElementId, - 'isLastPage' => $isLastPage, - 'oldFilter' => $oldFilter, + 'lastElementId' => $lastElementId, + 'isLastPage' => $isLastPage, + 'oldFilter' => $oldFilter, ]); $filter = array_merge( $oldFilter, [ - '>=ID' => $startElementId, + '>=ID' => $startElementId, $isLastPage ? '<=ID' : ' $lastElementId, ] ); @@ -544,11 +549,11 @@ protected function updateFilterForBatch(int $startElementId, int $lastElementId, * * work with start item position and elements count * - * @param string $apiMethod + * @param string $apiMethod * @param array $order - * @param array $filter - * @param array $select - * @param int|null $limit + * @param array $filter + * @param array $select + * @param int|null $limit * * @return Generator * @throws BaseException @@ -561,19 +566,20 @@ protected function updateFilterForBatch(int $startElementId, int $lastElementId, */ public function getTraversableListWithCount( string $apiMethod, - array $order, - array $filter, - array $select, - ?int $limit = null - ): Generator { + array $order, + array $filter, + array $select, + ?int $limit = null + ): Generator + { $this->logger->debug( 'getTraversableListWithCount.start', [ 'apiMethod' => $apiMethod, - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'limit' => $limit, + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'limit' => $limit, ] ); $this->clearCommands(); @@ -582,10 +588,10 @@ public function getTraversableListWithCount( $firstResult = $this->core->call( $apiMethod, [ - 'order' => $order, + 'order' => $order, 'filter' => $filter, 'select' => $select, - 'start' => 0, + 'start' => 0, ] ); @@ -595,7 +601,7 @@ public function getTraversableListWithCount( $this->logger->debug( 'getTraversableListWithCount.calculateCommandsRange', [ - 'nextItem' => $nextItem, + 'nextItem' => $nextItem, 'totalItems' => $total, ] ); @@ -606,10 +612,10 @@ public function getTraversableListWithCount( $this->registerCommand( $apiMethod, [ - 'order' => $order, + 'order' => $order, 'filter' => $filter, 'select' => $select, - 'start' => $startItem, + 'start' => $startItem, ] ); if ($limit !== null && $limit < $startItem) { @@ -621,10 +627,10 @@ public function getTraversableListWithCount( $this->registerCommand( $apiMethod, [ - 'order' => $order, + 'order' => $order, 'filter' => $filter, 'select' => $select, - 'start' => 0, + 'start' => 0, ] ); } @@ -632,7 +638,7 @@ public function getTraversableListWithCount( $this->logger->debug( 'getTraversableListWithCount.commandsRegistered', [ - 'commandsCount' => $this->commands->count(), + 'commandsCount' => $this->commands->count(), 'totalItemsToSelect' => $total, ] ); @@ -647,8 +653,8 @@ public function getTraversableListWithCount( 'getTraversableListWithCount.batchResultItem', [ 'batchCommandItemNumber' => $queryCnt, - 'nextItem' => $queryResultData->getPagination()->getNextItem(), - 'durationTime' => $queryResultData->getTime()->getDuration(), + 'nextItem' => $queryResultData->getPagination()->getNextItem(), + 'durationTime' => $queryResultData->getTime()->getDuration(), ] ); // iterate items in batch query result @@ -692,8 +698,8 @@ protected function getTraversable(bool $isHaltOnError): Generator $this->logger->debug( 'getTraversable.batchResultItem.processStart', [ - 'batchItemNumber' => $batchItem, - 'batchApiCommand' => $batchResult->getApiCommand()->getApiMethod(), + 'batchItemNumber' => $batchItem, + 'batchApiCommand' => $batchResult->getApiCommand()->getApiMethod(), 'batchApiCommandUuid' => $batchResult->getApiCommand()->getUuid()->toString(), ] ); @@ -765,7 +771,7 @@ private function getTraversableBatchResults(bool $isHaltOnError): Generator 'getTraversableBatchResults.batchQuery', [ 'batchQueryNumber' => $batchQueryCounter, - 'queriesCount' => count($batchQuery), + 'queriesCount' => count($batchQuery), ] ); // batch call diff --git a/src/Services/CRM/Contact/Service/Batch.php b/src/Services/CRM/Contact/Service/Batch.php index 696720a2..01383afe 100644 --- a/src/Services/CRM/Contact/Service/Batch.php +++ b/src/Services/CRM/Contact/Service/Batch.php @@ -7,6 +7,7 @@ use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Result\AddedItemBatchResult; use Bitrix24\SDK\Core\Result\DeletedItemBatchResult; +use Bitrix24\SDK\Core\Result\UpdatedItemBatchResult; use Bitrix24\SDK\Services\AbstractBatchService; use Bitrix24\SDK\Services\CRM\Contact\Result\ContactItemResult; use Generator; @@ -210,6 +211,28 @@ public function add(array $contacts): Generator } } + /** + * Batch update contacts + * + * Update elements in array with structure + * element_id => [ // contact id + * 'fields' => [], // contact fields to update + * 'params' => [] + * ] + * + * @param array $entityItems + * + * @param array $entityItems + * @return Generator + * @throws BaseException + */ + public function update(array $entityItems): Generator + { + foreach ($this->batch->updateEntityItems('crm.contact.update', $entityItems) as $key => $item) { + yield $key => new UpdatedItemBatchResult($item); + } + } + /** * Batch delete contact items * diff --git a/tests/Integration/Services/CRM/Contact/Service/ContactBatchTest.php b/tests/Integration/Services/CRM/Contact/Service/ContactBatchTest.php new file mode 100644 index 00000000..fafd8cb5 --- /dev/null +++ b/tests/Integration/Services/CRM/Contact/Service/ContactBatchTest.php @@ -0,0 +1,122 @@ +contactService->add(['NAME' => 'test contact']); + $cnt = 0; + + foreach ($this->contactService->batch->list([], ['>ID' => '1'], ['ID', 'NAME'], 1) as $item) { + $cnt++; + } + self::assertGreaterThanOrEqual(1, $cnt); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers \Bitrix24\SDK\Services\CRM\Contact\Service\Batch::add() + */ + public function testBatchAdd(): void + { + $contacts = []; + for ($i = 1; $i < 60; $i++) { + $contacts[] = ['NAME' => 'name-' . $i]; + } + $cnt = 0; + foreach ($this->contactService->batch->add($contacts) as $item) { + $cnt++; + } + + self::assertEquals(count($contacts), $cnt); + } + + /** + * @return void + * @throws BaseException + * @covers \Bitrix24\SDK\Services\CRM\Contact\Service\Batch::update() + */ + public function testBatchUpdate(): void + { + // add contacts + $contacts = []; + for ($i = 1; $i <= self::TEST_SEGMENT_ELEMENTS_COUNT; $i++) { + $contacts[] = [ + 'NAME' => 'name-' . time(), + 'SECOND_NAME' => 'second_name-' . time(), + 'LAST_NAME' => 'last_name-' . time(), + 'PHONE' => [ + [ + 'VALUE' => (new PhoneNumberBuilder())->build(), + 'VALUE_TYPE' => 'WORK' + ] + ] + ]; + } + $cnt = 0; + $contactId = []; + foreach ($this->contactService->batch->add($contacts) as $item) { + $cnt++; + $contactId[] = $item->getId(); + } + self::assertEquals(count($contacts), $cnt); + + // generate update data + $updateContactData = []; + foreach ($contactId as $id) { + $updateContactData[$id] = [ + 'fields' => [ + 'NAME' => 'name-' . $id . '-updated' + ], + ]; + } + + // update contacts in batch mode + $cnt = 0; + foreach ($this->contactService->batch->update($updateContactData) as $item) { + $cnt++; + $this->assertTrue($item->isSuccess()); + } + self::assertEquals(count($contacts), $cnt); + + // delete contacts + $cnt = 0; + foreach ($this->contactService->batch->delete($contactId) as $item) { + $cnt++; + $this->assertTrue($item->isSuccess()); + } + self::assertEquals(count($contacts), $cnt); + } + + public function setUp(): void + { + $this->contactService = Fabric::getServiceBuilder()->getCRMScope()->contact(); + } +} diff --git a/tests/Integration/Services/CRM/Contact/Service/ContactTest.php b/tests/Integration/Services/CRM/Contact/Service/ContactTest.php index 1be0b5e4..58d24b0f 100644 --- a/tests/Integration/Services/CRM/Contact/Service/ContactTest.php +++ b/tests/Integration/Services/CRM/Contact/Service/ContactTest.php @@ -87,35 +87,6 @@ public function testUpdate(): void self::assertEquals($newName, $this->contactService->get($contact->getId())->contact()->NAME); } - /** - * @throws BaseException - * @throws TransportException - */ - public function testBatchList(): void - { - $this->contactService->add(['NAME' => 'test contact']); - $cnt = 0; - - foreach ($this->contactService->batch->list([], ['>ID' => '1'], ['ID', 'NAME'], 1) as $item) { - $cnt++; - } - self::assertGreaterThanOrEqual(1, $cnt); - } - - public function testBatchAdd(): void - { - $contacts = []; - for ($i = 1; $i < 60; $i++) { - $contacts[] = ['NAME' => 'name-' . $i]; - } - $cnt = 0; - foreach ($this->contactService->batch->add($contacts) as $item) { - $cnt++; - } - - self::assertEquals(count($contacts), $cnt); - } - /** * @throws \Bitrix24\SDK\Core\Exceptions\TransportException * @throws \Bitrix24\SDK\Core\Exceptions\BaseException From a966704cf296e1f3b4c808ec50468a9302dba3b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=A5=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Mon, 3 Apr 2023 17:18:44 +0300 Subject: [PATCH 469/647] =?UTF-8?q?-=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=D0=B8=20=D0=B2=D1=8B=D0=B2=D0=BE=D0=B4=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D0=BF=D0=BE=D0=BA=D0=B0=D0=B7=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D1=81=D1=83=D0=BC=D0=BC=D0=B0=D1=80=D0=BD=D0=BE=D0=B3?= =?UTF-8?q?=D0=BE=20operating=20=D0=B2=D0=BE=20=D0=B2=D1=80=D0=B5=D0=BC?= =?UTF-8?q?=D1=8F=20=D0=B7=D0=B0=D0=BF=D1=80=D0=BE=D1=81=D0=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../OperatingTimingTest/OperatingTimingTest.php | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/tests/Integration/OperatingTimingTest/OperatingTimingTest.php b/tests/Integration/OperatingTimingTest/OperatingTimingTest.php index fb928de6..d83e6ea3 100644 --- a/tests/Integration/OperatingTimingTest/OperatingTimingTest.php +++ b/tests/Integration/OperatingTimingTest/OperatingTimingTest.php @@ -3,6 +3,7 @@ declare(strict_types=1); namespace Bitrix24\SDK\Tests\Integration\OperatingTimingTest; + use Bitrix24\SDK\Core\Batch; use Bitrix24\SDK\Services\CRM\Contact\Service\Contact; use Bitrix24\SDK\Tests\Integration\Fabric; @@ -25,21 +26,26 @@ class OperatingTimingTest extends TestCase public function testOperatingTiming(): void { - $cnt = 0; + $timeStart = microtime(true); $contactsToUpdate = []; - foreach ($this->contactService->batch->list([], ['>ID' => '103595'], ['ID','PHONE'], 30000) as $contactList) { - $cnt++; + foreach ($this->contactService->batch->list([], ['>ID' => '12'], ['ID', 'PHONE'], 30000) as $contactList) { $contactsToUpdate[$contactList->ID] = [ 'fields' => [ - 'PHONE' => [['ID' =>$contactList->PHONE[0]['ID']]] + 'PHONE' => [['ID' => $contactList->PHONE[0]['ID']]] ], 'params' => [], ]; $contactListId[] = $contactList->ID; } foreach ($this->contactService->batch->update($contactsToUpdate) as $dealUpdateResult) { - $this->assertTrue($dealUpdateResult->isSuccess()); + $logOperating[] = $dealUpdateResult->getResponseData()->getTime()->getOperating(); + $logOperatingResetAt = $dealUpdateResult->getResponseData()->getTime()->getOperatingResetAt(); + $sumOperating = array_sum($logOperating); + echo "summa operating: " . $sumOperating . PHP_EOL; + echo "operating rest at: " . $logOperatingResetAt . PHP_EOL; } + $timeEnd = microtime(true); + echo sprintf('batch query duration: %s seconds', round($timeEnd - $timeStart, 2)) . PHP_EOL; self::assertGreaterThanOrEqual(5, $contactListId); From f72a293e8aa3056080eff8e6fc0cf4a5dd7e44ab Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 16 Apr 2023 01:41:34 +0400 Subject: [PATCH 470/647] add some code for support operating timings Signed-off-by: mesilov --- src/Core/ApiLevelErrorHandler.php | 70 +++++++- src/Core/Core.php | 39 ++--- .../OperationTimeLimitExceededException.php | 14 ++ src/Core/Response/Response.php | 71 ++------ .../Integration/Core/OperatingTimingTest.php | 153 ++++++++++++++++++ .../OperatingTimingTest.php | 59 ------- tests/Unit/Core/ApiLevelErrorHandlerTest.php | 51 ++++++ tests/Unit/Stubs/NullCore.php | 5 +- 8 files changed, 320 insertions(+), 142 deletions(-) create mode 100644 src/Core/Exceptions/OperationTimeLimitExceededException.php create mode 100644 tests/Integration/Core/OperatingTimingTest.php delete mode 100644 tests/Integration/OperatingTimingTest/OperatingTimingTest.php create mode 100644 tests/Unit/Core/ApiLevelErrorHandlerTest.php diff --git a/src/Core/ApiLevelErrorHandler.php b/src/Core/ApiLevelErrorHandler.php index 685b9331..39b1d5df 100644 --- a/src/Core/ApiLevelErrorHandler.php +++ b/src/Core/ApiLevelErrorHandler.php @@ -6,6 +6,7 @@ use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Exceptions\MethodNotFoundException; +use Bitrix24\SDK\Core\Exceptions\OperationTimeLimitExceededException; use Bitrix24\SDK\Core\Exceptions\QueryLimitExceededException; use Psr\Log\LoggerInterface; @@ -33,33 +34,88 @@ public function __construct(LoggerInterface $logger) } /** - * @param array $responseBody + * @param array $responseBody * * @throws QueryLimitExceededException * @throws BaseException */ public function handle(array $responseBody): void { - if (!array_key_exists(self::ERROR_KEY, $responseBody)) { - $this->logger->debug('handle.noError'); + //ошибка единичного запроса + if (array_key_exists(self::ERROR_KEY, $responseBody) && array_key_exists(self::ERROR_DESCRIPTION_KEY, $responseBody)) { + $this->handleError($responseBody); + } + // ошибка в батче + if (!array_key_exists('result', $responseBody)) { return; } + if (array_key_exists('result_error', $responseBody['result'])) { + foreach ($responseBody['result']['result_error'] as $cmdId => $errorData) { + $this->handleError($errorData, $cmdId); + } + } + } + + /** + * @throws MethodNotFoundException + * @throws QueryLimitExceededException + * @throws BaseException + */ + private function handleError(array $responseBody, ?string $batchCommandId = null): void + { $errorCode = strtolower(trim((string)$responseBody[self::ERROR_KEY])); $errorDescription = strtolower(trim((string)$responseBody[self::ERROR_DESCRIPTION_KEY])); + $this->logger->debug( - 'handle.errorCode', + 'handle.errorInformation', [ 'errorCode' => $errorCode, + 'errorDescription' => $errorDescription, ] ); + + $batchErrorPrefix = ''; + if ($batchCommandId !== null) { + $batchErrorPrefix = sprintf(' batch command id: %s', $batchCommandId); + } + switch ($errorCode) { case 'query_limit_exceeded': - throw new QueryLimitExceededException('query limit exceeded - too many requests'); + throw new QueryLimitExceededException(sprintf('query limit exceeded - too many requests %s', $batchErrorPrefix)); case 'error_method_not_found': - throw new MethodNotFoundException('api method not found'); + throw new MethodNotFoundException(sprintf('api method not found %s %s', $errorDescription, $batchErrorPrefix)); + case 'operation_time_limit': + throw new OperationTimeLimitExceededException(sprintf('operation time limit exceeded %s %s', $errorDescription, $batchErrorPrefix)); default: - throw new BaseException(sprintf('%s - %s', $errorCode, $errorDescription)); + throw new BaseException(sprintf('%s - %s %s', $errorCode, $errorDescription, $batchErrorPrefix)); } + // switch (strtoupper(trim($apiResponse['error']))) { +// case 'EXPIRED_TOKEN': +// throw new Bitrix24TokenIsExpiredException($errorMsg); +// case 'WRONG_CLIENT': +// case 'ERROR_OAUTH': +// $this->log->error($errorMsg, $this->getErrorContext()); +// throw new Bitrix24WrongClientException($errorMsg); +// case 'ERROR_METHOD_NOT_FOUND': +// $this->log->error($errorMsg, $this->getErrorContext()); +// throw new Bitrix24MethodNotFoundException($errorMsg); +// case 'INVALID_TOKEN': +// case 'INVALID_GRANT': +// $this->log->error($errorMsg, $this->getErrorContext()); +// throw new Bitrix24TokenIsInvalidException($errorMsg); + +// case 'PAYMENT_REQUIRED': +// $this->log->error($errorMsg, $this->getErrorContext()); +// throw new Bitrix24PaymentRequiredException($errorMsg); +// case 'NO_AUTH_FOUND': +// $this->log->error($errorMsg, $this->getErrorContext()); +// throw new Bitrix24PortalRenamedException($errorMsg); +// case 'INSUFFICIENT_SCOPE': +// $this->log->error($errorMsg, $this->getErrorContext()); +// throw new Bitrix24InsufficientScope($errorMsg); +// default: +// $this->log->error($errorMsg, $this->getErrorContext()); +// throw new Bitrix24ApiException($errorMsg); } } \ No newline at end of file diff --git a/src/Core/Core.php b/src/Core/Core.php index 688bbe26..a739fe9a 100644 --- a/src/Core/Core.php +++ b/src/Core/Core.php @@ -32,17 +32,18 @@ class Core implements CoreInterface /** * Main constructor. * - * @param ApiClientInterface $apiClient - * @param ApiLevelErrorHandler $apiLevelErrorHandler + * @param ApiClientInterface $apiClient + * @param ApiLevelErrorHandler $apiLevelErrorHandler * @param EventDispatcherInterface $eventDispatcher - * @param LoggerInterface $logger + * @param LoggerInterface $logger */ public function __construct( - ApiClientInterface $apiClient, - ApiLevelErrorHandler $apiLevelErrorHandler, + ApiClientInterface $apiClient, + ApiLevelErrorHandler $apiLevelErrorHandler, EventDispatcherInterface $eventDispatcher, - LoggerInterface $logger - ) { + LoggerInterface $logger + ) + { $this->apiClient = $apiClient; $this->apiLevelErrorHandler = $apiLevelErrorHandler; $this->eventDispatcher = $eventDispatcher; @@ -51,7 +52,7 @@ public function __construct( /** * @param string $apiMethod - * @param array $parameters + * @param array $parameters * * @return Response * @throws BaseException @@ -62,7 +63,7 @@ public function call(string $apiMethod, array $parameters = []): Response $this->logger->debug( 'call.start', [ - 'method' => $apiMethod, + 'method' => $apiMethod, 'parameters' => $parameters, ] ); @@ -80,7 +81,7 @@ public function call(string $apiMethod, array $parameters = []): Response switch ($apiCallResponse->getStatusCode()) { case StatusCodeInterface::STATUS_OK: //todo check with empty response size from server - $response = new Response($apiCallResponse, new Command($apiMethod, $parameters), $this->logger); + $response = new Response($apiCallResponse, new Command($apiMethod, $parameters), $this->apiLevelErrorHandler, $this->logger); break; case StatusCodeInterface::STATUS_FOUND: // change domain url @@ -98,9 +99,9 @@ public function call(string $apiMethod, array $parameters = []): Response $this->logger->debug( 'api call repeated to new domain url', [ - 'domainUrl' => $portalNewDomainUrlHost, + 'domainUrl' => $portalNewDomainUrlHost, 'repeatedApiMethod' => $apiMethod, - 'httpStatusCode' => $response->getHttpResponse()->getStatusCode(), + 'httpStatusCode' => $response->getHttpResponse()->getStatusCode(), ] ); // dispatch event, application listeners update domain url host in accounts repository @@ -121,10 +122,10 @@ public function call(string $apiMethod, array $parameters = []): Response $this->logger->debug( 'access token renewed', [ - 'newAccessToken' => $renewedToken->getAccessToken()->getAccessToken(), + 'newAccessToken' => $renewedToken->getAccessToken()->getAccessToken(), 'newRefreshToken' => $renewedToken->getAccessToken()->getRefreshToken(), - 'newExpires' => $renewedToken->getAccessToken()->getExpires(), - 'appStatus' => $renewedToken->getApplicationStatus(), + 'newExpires' => $renewedToken->getAccessToken()->getExpires(), + 'appStatus' => $renewedToken->getApplicationStatus(), ] ); $this->apiClient->getCredentials()->setAccessToken($renewedToken->getAccessToken()); @@ -135,7 +136,7 @@ public function call(string $apiMethod, array $parameters = []): Response 'api call repeated', [ 'repeatedApiMethod' => $apiMethod, - 'httpStatusCode' => $response->getHttpResponse()->getStatusCode(), + 'httpStatusCode' => $response->getHttpResponse()->getStatusCode(), ] ); @@ -161,7 +162,7 @@ public function call(string $apiMethod, array $parameters = []): Response 'unhandled server status', [ 'httpStatus' => $apiCallResponse->getStatusCode(), - 'body' => $body, + 'body' => $body, ] ); $this->apiLevelErrorHandler->handle($body); @@ -172,7 +173,7 @@ public function call(string $apiMethod, array $parameters = []): Response $this->logger->error( 'call.transportException', [ - 'trace' => $exception->getTrace(), + 'trace' => $exception->getTrace(), 'message' => $exception->getMessage(), ] ); @@ -185,7 +186,7 @@ public function call(string $apiMethod, array $parameters = []): Response 'call.unknownException', [ 'message' => $exception->getMessage(), - 'trace' => $exception->getTrace(), + 'trace' => $exception->getTrace(), ] ); throw new BaseException(sprintf('unknown error - %s', $exception->getMessage()), $exception->getCode(), $exception); diff --git a/src/Core/Exceptions/OperationTimeLimitExceededException.php b/src/Core/Exceptions/OperationTimeLimitExceededException.php new file mode 100644 index 00000000..6311730e --- /dev/null +++ b/src/Core/Exceptions/OperationTimeLimitExceededException.php @@ -0,0 +1,14 @@ +httpResponse = $httpResponse; $this->apiCommand = $apiCommand; + $this->apiLevelErrorHandler = $apiLevelErrorHandler; $this->logger = $logger; $this->responseData = null; } @@ -64,16 +70,16 @@ public function __destruct() $restTimings = null; if ($this->responseData !== null) { $restTimings = [ - 'rest_query_duration' => $this->responseData->getTime()->getDuration(), + '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(), + 'rest_query_start' => $this->responseData->getTime()->getStart(), + 'rest_query_finish' => $this->responseData->getTime()->getFinish(), ]; } $this->logger->info('Response.TransportInfo', [ - 'restTimings' => $restTimings, + 'restTimings' => $restTimings, 'networkTimings' => (new NetworkTimingsParser($this->httpResponse->getInfo()))->toArrayWithMicroseconds(), - 'responseInfo' => (new ResponseInfoParser($this->httpResponse->getInfo()))->toArray(), + 'responseInfo' => (new ResponseInfoParser($this->httpResponse->getInfo()))->toArray(), ]); } @@ -92,8 +98,9 @@ public function getResponseData(): DTO\ResponseData $this->logger->info('getResponseData.responseBody', [ 'responseBody' => $responseResult, ]); + // try to handle api-level errors - $this->handleApiLevelErrors($responseResult); + $this->apiLevelErrorHandler->handle($responseResult); if (!is_array($responseResult['result'])) { $responseResult['result'] = [$responseResult['result']]; @@ -143,50 +150,4 @@ private function getHttpResponseContent(): ?string return $content; } - - /** - * @param array $apiResponse - */ - private function handleApiLevelErrors(array $apiResponse): void - { - $this->logger->debug('handleApiLevelErrors.start'); - - if (array_key_exists('error', $apiResponse)) { - $errorMsg = sprintf( - '%s - %s ', - $apiResponse['error'], - (array_key_exists('error_description', $apiResponse) ? $apiResponse['error_description'] : ''), - ); -// todo check api-level error codes -// -// switch (strtoupper(trim($apiResponse['error']))) { -// case 'EXPIRED_TOKEN': -// throw new Bitrix24TokenIsExpiredException($errorMsg); -// case 'WRONG_CLIENT': -// case 'ERROR_OAUTH': -// $this->log->error($errorMsg, $this->getErrorContext()); -// throw new Bitrix24WrongClientException($errorMsg); -// case 'ERROR_METHOD_NOT_FOUND': -// $this->log->error($errorMsg, $this->getErrorContext()); -// throw new Bitrix24MethodNotFoundException($errorMsg); -// case 'INVALID_TOKEN': -// case 'INVALID_GRANT': -// $this->log->error($errorMsg, $this->getErrorContext()); -// throw new Bitrix24TokenIsInvalidException($errorMsg); - -// case 'PAYMENT_REQUIRED': -// $this->log->error($errorMsg, $this->getErrorContext()); -// throw new Bitrix24PaymentRequiredException($errorMsg); -// case 'NO_AUTH_FOUND': -// $this->log->error($errorMsg, $this->getErrorContext()); -// throw new Bitrix24PortalRenamedException($errorMsg); -// case 'INSUFFICIENT_SCOPE': -// $this->log->error($errorMsg, $this->getErrorContext()); -// throw new Bitrix24InsufficientScope($errorMsg); -// default: -// $this->log->error($errorMsg, $this->getErrorContext()); -// throw new Bitrix24ApiException($errorMsg); - } - $this->logger->debug('handleApiLevelErrors.finish'); - } } \ No newline at end of file diff --git a/tests/Integration/Core/OperatingTimingTest.php b/tests/Integration/Core/OperatingTimingTest.php new file mode 100644 index 00000000..9eebac8b --- /dev/null +++ b/tests/Integration/Core/OperatingTimingTest.php @@ -0,0 +1,153 @@ +getContactsUpdateCommand(15000); + + + //todo считать количество контактов для обновления и считать количество контактов которые обновили, если не совпало, то падаем с ошибкой + + // обновляем контакты в батч-режиме + $cnt = 0; + foreach ($this->contactService->batch->update($contactsToUpdate) as $b24ContactId => $contactUpdateResult) { + $cnt++; + + $debugOperatingLog = sprintf( + 'cnt %s |id %s |operating %s |cur_time %s |op_reset_at %s → %s', + $cnt, + $b24ContactId, + $contactUpdateResult->getResponseData()->getTime()->getOperating(), + $contactUpdateResult->getResponseData()->getTime()->getDateFinish()->format('Y-m-d H:i:s'), + $contactUpdateResult->getResponseData()->getTime()->getOperatingResetAt(), + (new DateTime)->setTimestamp($contactUpdateResult->getResponseData()->getTime()->getOperatingResetAt())->format('Y-m-d H:i:s') + ) . PHP_EOL; + file_put_contents('operating.log', $debugOperatingLog); + } + + $this->assertEquals( + count($contactsToUpdate), + $cnt, + sprintf('updated contacts count %s not equal to expected %s cmd items', $cnt, count($contactsToUpdate)) + ); + + // шаг 1 - выброс корректного исключения, что мол упали из за блокировки метода + // проблемы: - можно потерять часть данных при обновлении, т.к. мы не знаем, какие контакты в клиентском коде обновились, а какие нет или знаем? + +// todo уточнение, по возможности возвращать в исключении остаток данных, которые не успели обновиться + +//[2023-04-15T14:17:57.881428+00:00] integration-test.INFO: getResponseData.responseBody {"responseBody": +//{"result": +//{ +// "result":[], +// "result_error": +// { +// "592dcd1e-cd14-410f-bab5-76b3ede717dd": +// { +// "error":"OPERATION_TIME_LIMIT", +// "error_description":"Method is blocked due to operation time limit." +// } +// }, +// "result_total":[], +// "result_next":[], +// "result_time":[]}, +// "time":{ +// "start":1681568278.071253, +// "finish":1681568278.097257, +// "duration":0.02600383758544922, +// "processing":0.0005891323089599609, +// "date_start":"2023-04-15T17:17:58+03:00", +// "date_finish":"2023-04-15T17:17:58+03:00", +// "operating_reset_at":1681568878, +// "operating":0 +// } +//} +//} {"file":"/Users/mesilov/work/msk03-dev/loyalty/bitrix24-php-sdk/src/Core/Response/Response.php","line":92,"class":"Bitrix24\\SDK\\Core\\Response\\Response","function":"getResponseData","memory_usage":"36 MB"} +//[2023-04-15T14:17:57.881514+00:00] integration-test.DEBUG: handleApiLevelErrors.start [] {"file":"/Users/mesilov/work/msk03-dev/loyalty/bitrix24-php-sdk/src/Core/Response/Response.php","line":152,"class":"Bitrix24\\SDK\\Core\\Response\\Response","function":"handleApiLevelErrors","memory_usage":"36 MB"} +//[2023-04-15T14:17:57.881645+00:00] integration-test.DEBUG: handleApiLevelErrors.finish [] {"file":"/Users/mesilov/work/msk03-dev/loyalty/bitrix24-php-sdk/src/Core/Response/Response.php","line":190,"class":"Bitrix24\\SDK\\Core\\Response\\Response","function":"handleApiLevelErrors","memory_usage":"36 MB"} +//[2023-04-15T14:17:57.881795+00:00] integration-test.DEBUG: getResponseData.parseResponse.finish [] +//[2023-04-15T14:37:47.371152+00:00] integration-test.INFO: getResponseData.responseBody {"responseBody":{"result":{"result":[],"result_error":{"f26b4ebc-3a82-4fe6-8d26-595d6eaf029b":{"error":"OPERATION_TIME_LIMIT","error_description":"Method is blocked due to operation time limit."}},"result_total":[],"result_next":[],"result_time":[]},"time":{"start":1681569467.49515,"finish":1681569467.519364,"duration":0.02421402931213379,"processing":0.0005979537963867188,"date_start":"2023-04-15T17:37:47+03:00","date_finish":"2023-04-15T17:37:47+03:00","operating_reset_at":1681570067,"operating":0}}} {"file":"/Users/mesilov/work/msk03-dev/loyalty/bitrix24-php-sdk/src/Core/Response/Response.php","line":92,"class":"Bitrix24\\SDK\\Core\\Response\\Response","function":"getResponseData","memory_usage":"36 MB"} +//[2023-04-15T14:37:47.371279+00:00] integration-test.DEBUG: handleApiLevelErrors.start [] {"file":"/Users/mesilov/work/msk03-dev/loyalty/bitrix24-php-sdk/src/Core/Response/Response.php","line":152,"class":"Bitrix24\\SDK\\Core\\Response\\Response","function":"handleApiLevelErrors","memory_usage":"36 MB"} + + + // шаг 2 - сделать отдельные стратегии с логикой для батча и придумать, как может быть + // - 2.1 ожидание разблокировки метода без завершения работы батча, т.е. скрипт будет висеть 10 минут, потом попробует продолжить работу, такое можно делать толкьо осознавая последсвия + // - 2.2 выброс события \ вызов обработчика за N секунд до блокировки метода, т.е делегируем логику обработки в клиентский код + + + } + + /** + * Get contacts for update command + * + * @param int $contactsToUpdateCount + * @return array + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + private function getContactsUpdateCommand(int $contactsToUpdateCount): array + { + $filter = ['>ID' => '1']; + + $contactsCount = $this->contactService->countByFilter($filter); + if ($contactsCount < $contactsToUpdateCount) { + throw new RuntimeException(sprintf('Not enough contacts for test. Need %s, but have %s', $contactsToUpdateCount, $contactsCount)); + } + + $contactsToUpdate = []; + foreach ($this->contactService->batch->list([], $filter, ['ID', 'COMMENTS'], $contactsToUpdateCount) as $b24Contact) { + $contactsToUpdate[$b24Contact->ID] = [ + 'fields' => [ + 'COMMENTS' => $b24Contact->COMMENTS . time() . PHP_EOL, + ], + 'params' => [], + ]; + } + return $contactsToUpdate; + } + + public function setUp(): void + { + $this->batch = Fabric::getBatchService(); + $this->contactService = Fabric::getServiceBuilder()->getCRMScope()->contact(); + } +} \ No newline at end of file diff --git a/tests/Integration/OperatingTimingTest/OperatingTimingTest.php b/tests/Integration/OperatingTimingTest/OperatingTimingTest.php deleted file mode 100644 index d83e6ea3..00000000 --- a/tests/Integration/OperatingTimingTest/OperatingTimingTest.php +++ /dev/null @@ -1,59 +0,0 @@ -contactService->batch->list([], ['>ID' => '12'], ['ID', 'PHONE'], 30000) as $contactList) { - $contactsToUpdate[$contactList->ID] = [ - 'fields' => [ - 'PHONE' => [['ID' => $contactList->PHONE[0]['ID']]] - ], - 'params' => [], - ]; - $contactListId[] = $contactList->ID; - } - foreach ($this->contactService->batch->update($contactsToUpdate) as $dealUpdateResult) { - $logOperating[] = $dealUpdateResult->getResponseData()->getTime()->getOperating(); - $logOperatingResetAt = $dealUpdateResult->getResponseData()->getTime()->getOperatingResetAt(); - $sumOperating = array_sum($logOperating); - echo "summa operating: " . $sumOperating . PHP_EOL; - echo "operating rest at: " . $logOperatingResetAt . PHP_EOL; - } - $timeEnd = microtime(true); - echo sprintf('batch query duration: %s seconds', round($timeEnd - $timeStart, 2)) . PHP_EOL; - - self::assertGreaterThanOrEqual(5, $contactListId); - - } - - public function setUp(): void - { - $this->batch = Fabric::getBatchService(); - $this->contactService = Fabric::getServiceBuilder()->getCRMScope()->contact(); - } -} \ No newline at end of file diff --git a/tests/Unit/Core/ApiLevelErrorHandlerTest.php b/tests/Unit/Core/ApiLevelErrorHandlerTest.php new file mode 100644 index 00000000..f8a96fee --- /dev/null +++ b/tests/Unit/Core/ApiLevelErrorHandlerTest.php @@ -0,0 +1,51 @@ +expectException(OperationTimeLimitExceededException::class); + + $response = [ + 'result' => [ + 'result' => [], + 'result_error' => [ + "592dcd1e-cd14-410f-bab5-76b3ede717dd" => [ + 'error' => 'OPERATION_TIME_LIMIT', + 'error_description' => 'Method is blocked due to operation time limit.' + ] + ] + ], + ]; + + $this->apiLevelErrorHandler->handle($response); + } + + public function setUp(): void + { + $this->apiLevelErrorHandler = new ApiLevelErrorHandler(new NullLogger()); + } +} diff --git a/tests/Unit/Stubs/NullCore.php b/tests/Unit/Stubs/NullCore.php index 493da934..209c064b 100644 --- a/tests/Unit/Stubs/NullCore.php +++ b/tests/Unit/Stubs/NullCore.php @@ -5,6 +5,7 @@ namespace Bitrix24\SDK\Tests\Unit\Stubs; use Bitrix24\SDK\Core\ApiClient; +use Bitrix24\SDK\Core\ApiLevelErrorHandler; use Bitrix24\SDK\Core\Commands\Command; use Bitrix24\SDK\Core\Contracts\ApiClientInterface; use Bitrix24\SDK\Core\Contracts\CoreInterface; @@ -24,14 +25,14 @@ class NullCore implements CoreInterface { /** * @param string $apiMethod - * @param array $parameters + * @param array $parameters * * @return Response * @throws \Exception */ public function call(string $apiMethod, array $parameters = []): Response { - return new Response(new MockResponse(''), new Command('', []), new NullLogger()); + return new Response(new MockResponse(''), new Command('', []), new ApiLevelErrorHandler(new NullLogger()), new NullLogger()); } public function getApiClient(): ApiClientInterface From b4c54b5b0d222a729992c10f7ec67f1b5479714d Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 6 Aug 2023 17:49:06 +0400 Subject: [PATCH 471/647] fix errors after refactoring Signed-off-by: mesilov --- src/Core/ApiLevelErrorHandler.php | 13 +++-- .../Core => Temp}/OperatingTimingTest.php | 54 +++++++++---------- 2 files changed, 35 insertions(+), 32 deletions(-) rename tests/{Integration/Core => Temp}/OperatingTimingTest.php (83%) diff --git a/src/Core/ApiLevelErrorHandler.php b/src/Core/ApiLevelErrorHandler.php index 39b1d5df..b25deaee 100644 --- a/src/Core/ApiLevelErrorHandler.php +++ b/src/Core/ApiLevelErrorHandler.php @@ -21,6 +21,8 @@ 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'; /** @@ -41,17 +43,18 @@ public function __construct(LoggerInterface $logger) */ public function handle(array $responseBody): void { - //ошибка единичного запроса + // single query error response if (array_key_exists(self::ERROR_KEY, $responseBody) && array_key_exists(self::ERROR_DESCRIPTION_KEY, $responseBody)) { $this->handleError($responseBody); } - // ошибка в батче - if (!array_key_exists('result', $responseBody)) { + // error in batch response + if (!array_key_exists(self::RESULT_KEY, $responseBody) || (!is_array($responseBody[self::RESULT_KEY]))) { return; } - if (array_key_exists('result_error', $responseBody['result'])) { - foreach ($responseBody['result']['result_error'] as $cmdId => $errorData) { + + if (array_key_exists(self::RESULT_ERROR_KEY, $responseBody[self::RESULT_KEY])) { + foreach ($responseBody[self::RESULT_KEY][self::RESULT_ERROR_KEY] as $cmdId => $errorData) { $this->handleError($errorData, $cmdId); } } diff --git a/tests/Integration/Core/OperatingTimingTest.php b/tests/Temp/OperatingTimingTest.php similarity index 83% rename from tests/Integration/Core/OperatingTimingTest.php rename to tests/Temp/OperatingTimingTest.php index 9eebac8b..50ffbb87 100644 --- a/tests/Integration/Core/OperatingTimingTest.php +++ b/tests/Temp/OperatingTimingTest.php @@ -43,33 +43,33 @@ public function testOperatingTiming(): void //1510 |operating 104.5405356884 |cur_time 2023-04-15 16:57:21 |op_reset_at 1681567640 → 2023-04-15 14:07:20 - $contactsToUpdate = $this->getContactsUpdateCommand(15000); - - - //todo считать количество контактов для обновления и считать количество контактов которые обновили, если не совпало, то падаем с ошибкой - - // обновляем контакты в батч-режиме - $cnt = 0; - foreach ($this->contactService->batch->update($contactsToUpdate) as $b24ContactId => $contactUpdateResult) { - $cnt++; - - $debugOperatingLog = sprintf( - 'cnt %s |id %s |operating %s |cur_time %s |op_reset_at %s → %s', - $cnt, - $b24ContactId, - $contactUpdateResult->getResponseData()->getTime()->getOperating(), - $contactUpdateResult->getResponseData()->getTime()->getDateFinish()->format('Y-m-d H:i:s'), - $contactUpdateResult->getResponseData()->getTime()->getOperatingResetAt(), - (new DateTime)->setTimestamp($contactUpdateResult->getResponseData()->getTime()->getOperatingResetAt())->format('Y-m-d H:i:s') - ) . PHP_EOL; - file_put_contents('operating.log', $debugOperatingLog); - } - - $this->assertEquals( - count($contactsToUpdate), - $cnt, - sprintf('updated contacts count %s not equal to expected %s cmd items', $cnt, count($contactsToUpdate)) - ); +// $contactsToUpdate = $this->getContactsUpdateCommand(15000); +// +// +// //todo считать количество контактов для обновления и считать количество контактов которые обновили, если не совпало, то падаем с ошибкой +// +// // обновляем контакты в батч-режиме +// $cnt = 0; +// foreach ($this->contactService->batch->update($contactsToUpdate) as $b24ContactId => $contactUpdateResult) { +// $cnt++; +// +// $debugOperatingLog = sprintf( +// 'cnt %s |id %s |operating %s |cur_time %s |op_reset_at %s → %s', +// $cnt, +// $b24ContactId, +// $contactUpdateResult->getResponseData()->getTime()->getOperating(), +// $contactUpdateResult->getResponseData()->getTime()->getDateFinish()->format('Y-m-d H:i:s'), +// $contactUpdateResult->getResponseData()->getTime()->getOperatingResetAt(), +// (new DateTime)->setTimestamp($contactUpdateResult->getResponseData()->getTime()->getOperatingResetAt())->format('Y-m-d H:i:s') +// ) . PHP_EOL; +// file_put_contents('operating.log', $debugOperatingLog); +// } +// +// $this->assertEquals( +// count($contactsToUpdate), +// $cnt, +// sprintf('updated contacts count %s not equal to expected %s cmd items', $cnt, count($contactsToUpdate)) +// ); // шаг 1 - выброс корректного исключения, что мол упали из за блокировки метода // проблемы: - можно потерять часть данных при обновлении, т.к. мы не знаем, какие контакты в клиентском коде обновились, а какие нет или знаем? From 324b587dd83e6facd6afae4bcff951d46564a301 Mon Sep 17 00:00:00 2001 From: mesilov Date: Tue, 8 Aug 2023 02:48:27 +0400 Subject: [PATCH 472/647] add batch support for crm-items Signed-off-by: mesilov --- src/Core/Batch.php | 273 +++++++++++------- .../Contracts/BatchOperationsInterface.php | 9 +- 2 files changed, 166 insertions(+), 116 deletions(-) diff --git a/src/Core/Batch.php b/src/Core/Batch.php index d4123b87..4c30f8c7 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -34,7 +34,7 @@ class Batch implements BatchOperationsInterface /** * Batch constructor. * - * @param CoreInterface $core + * @param CoreInterface $core * @param LoggerInterface $log */ public function __construct(CoreInterface $core, LoggerInterface $log) @@ -62,7 +62,7 @@ protected function clearCommands(): void /** * Add entity items with batch call * - * @param string $apiMethod + * @param string $apiMethod * @param array $entityItems * * @return Generator|ResponseData[] @@ -73,7 +73,7 @@ public function addEntityItems(string $apiMethod, array $entityItems): Generator $this->logger->debug( 'addEntityItems.start', [ - 'apiMethod' => $apiMethod, + 'apiMethod' => $apiMethod, 'entityItems' => $entityItems, ] ); @@ -105,7 +105,7 @@ public function addEntityItems(string $apiMethod, array $entityItems): Generator /** * Delete entity items with batch call * - * @param string $apiMethod + * @param string $apiMethod * @param array $entityItemId * * @return Generator|ResponseData[] @@ -116,7 +116,7 @@ public function deleteEntityItems(string $apiMethod, array $entityItemId): Gener $this->logger->debug( 'deleteEntityItems.start', [ - 'apiMethod' => $apiMethod, + 'apiMethod' => $apiMethod, 'entityItems' => $entityItemId, ] ); @@ -173,7 +173,7 @@ public function deleteEntityItems(string $apiMethod, array $entityItemId): Gener * 'params' => [] // optional fields * ] * - * @param string $apiMethod + * @param string $apiMethod * @param array> $entityItems * * @return Generator|ResponseData[] @@ -184,7 +184,7 @@ public function updateEntityItems(string $apiMethod, array $entityItems): Genera $this->logger->debug( 'updateEntityItems.start', [ - 'apiMethod' => $apiMethod, + 'apiMethod' => $apiMethod, 'entityItems' => $entityItems, ] ); @@ -208,7 +208,7 @@ public function updateEntityItems(string $apiMethod, array $entityItems): Genera } $this->registerCommand($apiMethod, [ - 'id' => $entityItemId, + 'id' => $entityItemId, 'fields' => $entityItem['fields'], 'params' => $entityItem['params'], ]); @@ -244,24 +244,25 @@ public function updateEntityItems(string $apiMethod, array $entityItems): Genera /** * Register api command to command collection for batch calls * - * @param string $apiMethod + * @param string $apiMethod * @param array $parameters - * @param string|null $commandName - * @param callable|null $callback not implemented + * @param string|null $commandName + * @param callable|null $callback not implemented * * @throws \Exception */ protected function registerCommand( - string $apiMethod, - array $parameters = [], - ?string $commandName = null, + string $apiMethod, + array $parameters = [], + ?string $commandName = null, callable $callback = null - ): void { + ): void + { $this->logger->debug( 'registerCommand.start', [ - 'apiMethod' => $apiMethod, - 'parameters' => $parameters, + 'apiMethod' => $apiMethod, + 'parameters' => $parameters, 'commandName' => $commandName, ] ); @@ -317,11 +318,11 @@ protected function getReverseOrder(array $order): array /** * Get traversable list without count elements * - * @param string $apiMethod + * @param string $apiMethod * @param array $order - * @param array $filter - * @param array $select - * @param int|null $limit + * @param array $filter + * @param array $select + * @param int|null $limit * * @return \Generator * @throws \Bitrix24\SDK\Core\Exceptions\BaseException @@ -333,19 +334,22 @@ protected function getReverseOrder(array $order): array */ public function getTraversableList( string $apiMethod, - array $order, - array $filter, - array $select, - ?int $limit = null - ): Generator { + array $order, + array $filter, + array $select, + ?int $limit = null, + ?array $additionalParameters = null + ): Generator + { $this->logger->debug( 'getTraversableList.start', [ 'apiMethod' => $apiMethod, - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'limit' => $limit, + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'limit' => $limit, + 'additionalParameters' => $additionalParameters, ] ); @@ -376,15 +380,28 @@ public function getTraversableList( // todo проверили, что если есть limit, то он >1 // todo проверили, что в фильтре нет поля ID, т.к. мы с ним будем работать - $firstResultPage = $this->core->call( - $apiMethod, - [ - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'start' => 0, - ] - ); + $params = [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => 0, + ]; + + // data structures for crm.items.* is little different =\ + $isCrmItemsInBatch = false; + if ($additionalParameters !== null) { + if (array_key_exists('entityTypeId', $additionalParameters)) { + $isCrmItemsInBatch = true; + } + $params = array_merge($params, $additionalParameters); + } + + if ($isCrmItemsInBatch) { + $keyId = 'id'; + } else { + $keyId = 'ID'; + } + $firstResultPage = $this->core->call($apiMethod, $params); $totalElementsCount = $firstResultPage->getResponseData()->getPagination()->getTotal(); $this->logger->debug('getTraversableList.totalElementsCount', [ 'totalElementsCount' => $totalElementsCount, @@ -407,31 +424,46 @@ public function getTraversableList( // filtered elements count more than one result page(50 elements) // return first page $lastElementIdInFirstPage = null; - foreach ($firstResultPage->getResponseData()->getResult() as $cnt => $listElement) { - $elementsCounter++; - $lastElementIdInFirstPage = (int)$listElement['ID']; - if ($limit !== null && $elementsCounter > $limit) { - return; + if ($isCrmItemsInBatch) { + foreach ($firstResultPage->getResponseData()->getResult()['items'] as $cnt => $listElement) { + $elementsCounter++; + $lastElementIdInFirstPage = (int)$listElement[$keyId]; + if ($limit !== null && $elementsCounter > $limit) { + return; + } + yield $listElement; + } + } else { + foreach ($firstResultPage->getResponseData()->getResult() as $cnt => $listElement) { + $elementsCounter++; + $lastElementIdInFirstPage = (int)$listElement[$keyId]; + if ($limit !== null && $elementsCounter > $limit) { + return; + } + yield $listElement; } - yield $listElement; } $this->clearCommands(); - if (!in_array('ID', $select, true)) { - $select[] = 'ID'; + if (!in_array($keyId, $select, true)) { + $select[] = $keyId; } - // getLastElementId in filtered result - $lastResultPage = $this->core->call( - $apiMethod, - [ - 'order' => $this->getReverseOrder($order), - 'filter' => $filter, - 'select' => $select, - 'start' => 0, - ] - ); - $lastElementId = (int)$lastResultPage->getResponseData()->getResult()[0]['ID']; + $params = [ + 'order' => $this->getReverseOrder($order), + 'filter' => $filter, + 'select' => $select, + 'start' => 0, + ]; + if ($additionalParameters !== null) { + $params = array_merge($params, $additionalParameters); + } + $lastResultPage = $this->core->call($apiMethod, $params); + if ($isCrmItemsInBatch) { + $lastElementId = (int)$lastResultPage->getResponseData()->getResult()['items'][0][$keyId]; + } else { + $lastElementId = (int)$lastResultPage->getResponseData()->getResult()[0][$keyId]; + } // reverse order if you need if ($lastElementIdInFirstPage > $lastElementId) { $tmp = $lastElementIdInFirstPage; @@ -440,7 +472,7 @@ public function getTraversableList( } $this->logger->debug('getTraversableList.lastElementsId', [ 'lastElementIdInFirstPage' => $lastElementIdInFirstPage, - 'lastElementId' => $lastElementId, + 'lastElementId' => $lastElementId, ]); // register commands with updated filter @@ -448,9 +480,9 @@ public function getTraversableList( $lastElementIdInFirstPage++; for ($startId = $lastElementIdInFirstPage; $startId <= $lastElementId; $startId += self::MAX_ELEMENTS_IN_PAGE) { $this->logger->debug('registerCommand.item', [ - 'startId' => $startId, + 'startId' => $startId, 'lastElementId' => $lastElementId, - 'delta' => $lastElementId - $startId, + 'delta' => $lastElementId - $startId, ]); $delta = $lastElementId - $startId; @@ -465,15 +497,17 @@ public function getTraversableList( $isLastPage = true; } - $this->registerCommand( - $apiMethod, - [ - 'order' => [], - 'filter' => $this->updateFilterForBatch($startId, $lastElementIdInPage, $isLastPage, $filter), - 'select' => $select, - 'start' => -1, - ] - ); + $params = [ + 'order' => [], + 'filter' => $this->updateFilterForBatch($keyId, $startId, $lastElementIdInPage, $isLastPage, $filter), + 'select' => $select, + 'start' => -1, + ]; + if ($additionalParameters !== null) { + $params = array_merge($params, $additionalParameters); + } + + $this->registerCommand($apiMethod, $params); } $this->logger->debug( 'getTraversableList.commandsRegistered', @@ -492,44 +526,58 @@ public function getTraversableList( 'getTraversableList.batchResultItem', [ 'batchCommandItemNumber' => $queryCnt, - 'nextItem' => $queryResultData->getPagination()->getNextItem(), - 'durationTime' => $queryResultData->getTime()->getDuration(), + 'nextItem' => $queryResultData->getPagination()->getNextItem(), + 'durationTime' => $queryResultData->getTime()->getDuration(), ] ); + // iterate items in batch query result - foreach ($queryResultData->getResult() as $cnt => $listElement) { - $elementsCounter++; - if ($limit !== null && $elementsCounter > $limit) { - return; + if ($isCrmItemsInBatch) { + foreach ($queryResultData->getResult()['items'] as $cnt => $listElement) { + $elementsCounter++; + if ($limit !== null && $elementsCounter > $limit) { + return; + } + yield $listElement; + } + } else { + foreach ($queryResultData->getResult() as $cnt => $listElement) { + $elementsCounter++; + if ($limit !== null && $elementsCounter > $limit) { + return; + } + yield $listElement; } - yield $listElement; } + } $this->logger->debug('getTraversableList.finish'); } /** - * @param int $startElementId - * @param int $lastElementId - * @param bool $isLastPage + * @param string $keyId + * @param int $startElementId + * @param int $lastElementId + * @param bool $isLastPage * @param array $oldFilter * * @return array */ - protected function updateFilterForBatch(int $startElementId, int $lastElementId, bool $isLastPage, array $oldFilter): array + protected function updateFilterForBatch(string $keyId, int $startElementId, int $lastElementId, bool $isLastPage, array $oldFilter): array { $this->logger->debug('updateFilterForBatch.start', [ 'startElementId' => $startElementId, - 'lastElementId' => $lastElementId, - 'isLastPage' => $isLastPage, - 'oldFilter' => $oldFilter, + 'lastElementId' => $lastElementId, + 'isLastPage' => $isLastPage, + 'oldFilter' => $oldFilter, + 'key' => $keyId, ]); $filter = array_merge( $oldFilter, [ - '>=ID' => $startElementId, - $isLastPage ? '<=ID' : ' $lastElementId, + sprintf('>=%s', $keyId) => $startElementId, + $isLastPage ? sprintf('<=%s', $keyId) : sprintf('<%s', $keyId) => $lastElementId, ] ); $this->logger->debug('updateFilterForBatch.finish', [ @@ -544,11 +592,11 @@ protected function updateFilterForBatch(int $startElementId, int $lastElementId, * * work with start item position and elements count * - * @param string $apiMethod + * @param string $apiMethod * @param array $order - * @param array $filter - * @param array $select - * @param int|null $limit + * @param array $filter + * @param array $select + * @param int|null $limit * * @return Generator * @throws BaseException @@ -561,19 +609,20 @@ protected function updateFilterForBatch(int $startElementId, int $lastElementId, */ public function getTraversableListWithCount( string $apiMethod, - array $order, - array $filter, - array $select, - ?int $limit = null - ): Generator { + array $order, + array $filter, + array $select, + ?int $limit = null + ): Generator + { $this->logger->debug( 'getTraversableListWithCount.start', [ 'apiMethod' => $apiMethod, - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'limit' => $limit, + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'limit' => $limit, ] ); $this->clearCommands(); @@ -582,10 +631,10 @@ public function getTraversableListWithCount( $firstResult = $this->core->call( $apiMethod, [ - 'order' => $order, + 'order' => $order, 'filter' => $filter, 'select' => $select, - 'start' => 0, + 'start' => 0, ] ); @@ -595,7 +644,7 @@ public function getTraversableListWithCount( $this->logger->debug( 'getTraversableListWithCount.calculateCommandsRange', [ - 'nextItem' => $nextItem, + 'nextItem' => $nextItem, 'totalItems' => $total, ] ); @@ -606,10 +655,10 @@ public function getTraversableListWithCount( $this->registerCommand( $apiMethod, [ - 'order' => $order, + 'order' => $order, 'filter' => $filter, 'select' => $select, - 'start' => $startItem, + 'start' => $startItem, ] ); if ($limit !== null && $limit < $startItem) { @@ -621,10 +670,10 @@ public function getTraversableListWithCount( $this->registerCommand( $apiMethod, [ - 'order' => $order, + 'order' => $order, 'filter' => $filter, 'select' => $select, - 'start' => 0, + 'start' => 0, ] ); } @@ -632,7 +681,7 @@ public function getTraversableListWithCount( $this->logger->debug( 'getTraversableListWithCount.commandsRegistered', [ - 'commandsCount' => $this->commands->count(), + 'commandsCount' => $this->commands->count(), 'totalItemsToSelect' => $total, ] ); @@ -647,8 +696,8 @@ public function getTraversableListWithCount( 'getTraversableListWithCount.batchResultItem', [ 'batchCommandItemNumber' => $queryCnt, - 'nextItem' => $queryResultData->getPagination()->getNextItem(), - 'durationTime' => $queryResultData->getTime()->getDuration(), + 'nextItem' => $queryResultData->getPagination()->getNextItem(), + 'durationTime' => $queryResultData->getTime()->getDuration(), ] ); // iterate items in batch query result @@ -692,8 +741,8 @@ protected function getTraversable(bool $isHaltOnError): Generator $this->logger->debug( 'getTraversable.batchResultItem.processStart', [ - 'batchItemNumber' => $batchItem, - 'batchApiCommand' => $batchResult->getApiCommand()->getApiMethod(), + 'batchItemNumber' => $batchItem, + 'batchApiCommand' => $batchResult->getApiCommand()->getApiMethod(), 'batchApiCommandUuid' => $batchResult->getApiCommand()->getUuid()->toString(), ] ); @@ -765,7 +814,7 @@ private function getTraversableBatchResults(bool $isHaltOnError): Generator 'getTraversableBatchResults.batchQuery', [ 'batchQueryNumber' => $batchQueryCounter, - 'queriesCount' => count($batchQuery), + 'queriesCount' => count($batchQuery), ] ); // batch call diff --git a/src/Core/Contracts/BatchOperationsInterface.php b/src/Core/Contracts/BatchOperationsInterface.php index 801beab6..f6e5b55c 100644 --- a/src/Core/Contracts/BatchOperationsInterface.php +++ b/src/Core/Contracts/BatchOperationsInterface.php @@ -18,12 +18,12 @@ interface BatchOperationsInterface /** * Batch wrapper for *.list methods without counting elements on every api-call * - * @param string $apiMethod + * @param string $apiMethod * @param array $order * @param array $filter * @param array $select - * @param int|null $limit - * + * @param int|null $limit + * @param array|null $additionalParameters * @return Generator * @throws BaseException */ @@ -32,7 +32,8 @@ public function getTraversableList( array $order, array $filter, array $select, - ?int $limit = null + ?int $limit = null, + ?array $additionalParameters = null ): Generator; /** From 8243632c6ac281d9173aab491ff357cc14cb3999 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 13 Aug 2023 19:06:06 +0400 Subject: [PATCH 473/647] add crm-item with batch support Signed-off-by: mesilov --- CHANGELOG.md | 1 + src/Services/CRM/CRMServiceBuilder.php | 62 ++----- .../CRM/Common/Result/AbstractCrmItem.php | 51 ++++-- .../CRM/Item/Result/ItemItemResult.php | 53 ++++++ src/Services/CRM/Item/Result/ItemResult.php | 16 ++ src/Services/CRM/Item/Result/ItemsResult.php | 25 +++ src/Services/CRM/Item/Service/Batch.php | 68 ++++++++ src/Services/CRM/Item/Service/Item.php | 158 ++++++++++++++++++ 8 files changed, 372 insertions(+), 62 deletions(-) create mode 100644 src/Services/CRM/Item/Result/ItemItemResult.php create mode 100644 src/Services/CRM/Item/Result/ItemResult.php create mode 100644 src/Services/CRM/Item/Result/ItemsResult.php create mode 100644 src/Services/CRM/Item/Service/Batch.php create mode 100644 src/Services/CRM/Item/Service/Item.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 34531975..dbd28db7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ * `Bitrix24\SDK\Services\User\Service\User::get` - get user * `Bitrix24\SDK\Services\User\Service\User::update` - update user * `Bitrix24\SDK\Services\User\Service\User::search` - search users +* add [crm item support](https://github.com/mesilov/bitrix24-php-sdk/issues/330) ### Changed diff --git a/src/Services/CRM/CRMServiceBuilder.php b/src/Services/CRM/CRMServiceBuilder.php index 7bd84b03..f78a34ae 100644 --- a/src/Services/CRM/CRMServiceBuilder.php +++ b/src/Services/CRM/CRMServiceBuilder.php @@ -5,22 +5,9 @@ namespace Bitrix24\SDK\Services\CRM; use Bitrix24\SDK\Services\AbstractServiceBuilder; -use Bitrix24\SDK\Services\CRM\Contact; -use Bitrix24\SDK\Services\CRM\Deal; -use Bitrix24\SDK\Services\CRM\Product; -use Bitrix24\SDK\Services\CRM\Settings; - -/** - * Class CRMServiceBuilder - * - * @package Bitrix24\SDK\Services\CRM - */ class CRMServiceBuilder extends AbstractServiceBuilder { - /** - * @return Settings\Service\Settings - */ public function settings(): Settings\Service\Settings { if (!isset($this->serviceCache[__METHOD__])) { @@ -30,9 +17,6 @@ public function settings(): Settings\Service\Settings return $this->serviceCache[__METHOD__]; } - /** - * @return Deal\Service\DealContact - */ public function dealContact(): Deal\Service\DealContact { if (!isset($this->serviceCache[__METHOD__])) { @@ -42,9 +26,6 @@ public function dealContact(): Deal\Service\DealContact return $this->serviceCache[__METHOD__]; } - /** - * @return Deal\Service\DealCategory - */ public function dealCategory(): Deal\Service\DealCategory { if (!isset($this->serviceCache[__METHOD__])) { @@ -54,9 +35,6 @@ public function dealCategory(): Deal\Service\DealCategory return $this->serviceCache[__METHOD__]; } - /** - * @return Deal\Service\Deal - */ public function deal(): Deal\Service\Deal { if (!isset($this->serviceCache[__METHOD__])) { @@ -70,9 +48,6 @@ public function deal(): Deal\Service\Deal return $this->serviceCache[__METHOD__]; } - /** - * @return \Bitrix24\SDK\Services\CRM\Deal\Service\DealUserfield - */ public function dealUserfield(): Deal\Service\DealUserfield { if (!isset($this->serviceCache[__METHOD__])) { @@ -85,9 +60,6 @@ public function dealUserfield(): Deal\Service\DealUserfield return $this->serviceCache[__METHOD__]; } - /** - * @return Contact\Service\Contact - */ public function contact(): Contact\Service\Contact { if (!isset($this->serviceCache[__METHOD__])) { @@ -101,9 +73,6 @@ public function contact(): Contact\Service\Contact return $this->serviceCache[__METHOD__]; } - /** - * @return \Bitrix24\SDK\Services\CRM\Contact\Service\ContactUserfield - */ public function contactUserfield(): Contact\Service\ContactUserfield { if (!isset($this->serviceCache[__METHOD__])) { @@ -128,9 +97,6 @@ public function dealProductRows(): Deal\Service\DealProductRows return $this->serviceCache[__METHOD__]; } - /** - * @return Deal\Service\DealCategoryStage - */ public function dealCategoryStage(): Deal\Service\DealCategoryStage { if (!isset($this->serviceCache[__METHOD__])) { @@ -140,9 +106,6 @@ public function dealCategoryStage(): Deal\Service\DealCategoryStage return $this->serviceCache[__METHOD__]; } - /** - * @return Product\Service\Product - */ public function product(): Product\Service\Product { if (!isset($this->serviceCache[__METHOD__])) { @@ -156,9 +119,6 @@ public function product(): Product\Service\Product return $this->serviceCache[__METHOD__]; } - /** - * @return Userfield\Service\Userfield - */ public function userfield(): Userfield\Service\Userfield { if (!isset($this->serviceCache[__METHOD__])) { @@ -171,9 +131,6 @@ public function userfield(): Userfield\Service\Userfield return $this->serviceCache[__METHOD__]; } - /** - * @return Lead\Service\Lead - */ public function lead(): Lead\Service\Lead { if (!isset($this->serviceCache[__METHOD__])) { @@ -187,9 +144,6 @@ public function lead(): Lead\Service\Lead return $this->serviceCache[__METHOD__]; } - /** - * @return Activity\Service\Activity - */ public function activity(): Activity\Service\Activity { if (!isset($this->serviceCache[__METHOD__])) { @@ -203,9 +157,6 @@ public function activity(): Activity\Service\Activity return $this->serviceCache[__METHOD__]; } - /** - * @return Activity\ActivityFetcherBuilder - */ public function activityFetcher(): Activity\ActivityFetcherBuilder { if (!isset($this->serviceCache[__METHOD__])) { @@ -219,4 +170,17 @@ public function activityFetcher(): Activity\ActivityFetcherBuilder return $this->serviceCache[__METHOD__]; } + + public function item(): Item\Service\Item + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Item\Service\Item( + new Item\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } } \ No newline at end of file diff --git a/src/Services/CRM/Common/Result/AbstractCrmItem.php b/src/Services/CRM/Common/Result/AbstractCrmItem.php index eaf28aa5..81467927 100644 --- a/src/Services/CRM/Common/Result/AbstractCrmItem.php +++ b/src/Services/CRM/Common/Result/AbstractCrmItem.php @@ -15,7 +15,7 @@ class AbstractCrmItem extends AbstractItem private const CRM_USERFIELD_PREFIX = 'UF_CRM_'; /** - * @var \Money\Currency + * @var Currency */ private Currency $currency; @@ -25,7 +25,6 @@ public function __construct(array $data, Currency $currency = null) if ($currency !== null) { $this->currency = $currency; } - } /** @@ -49,6 +48,15 @@ public function __get($offset) case 'ASSIGNED_BY_ID': case 'CREATED_BY_ID': case 'MODIFY_BY_ID': + case 'createdBy': + case 'updatedBy': + case 'movedBy': + case 'begindate': + case 'closedate': + case 'opportunity': + case 'opportunityAccount': + case 'taxValueAccount': + case 'taxValue': // deal case 'LEAD_ID': case 'CONTACT_ID': @@ -57,12 +65,20 @@ public function __get($offset) case 'OWNER_ID': // DealCategoryItem case 'SORT': + case 'id': + case 'categoryId': + case 'webformId': + case 'assignedById': + case 'contactId': + case 'lastActivityBy': if ($this->data[$offset] !== '' && $this->data[$offset] !== null) { return (int)$this->data[$offset]; } return null; case 'COMPANY_ID': + case 'companyId': + case 'mycompanyId': if ($this->data[$offset] !== '' && $this->data[$offset] !== null && $this->data[$offset] !== '0') { return (int)$this->data[$offset]; } @@ -73,17 +89,9 @@ public function __get($offset) case 'HAS_EMAIL': case 'HAS_IMOL': case 'OPENED': - // deal - case 'PRICE_EXCLUSIVE': - case 'PRICE_NETTO': - case 'PRICE_BRUTTO': - case 'PRICE': - 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 'opened': case 'IS_MANUAL_OPPORTUNITY': + case 'isManualOpportunity': case 'CLOSED': case 'IS_NEW': case 'IS_LOCKED': @@ -97,11 +105,28 @@ public function __get($offset) case 'BIRTHDATE': case 'BEGINDATE': case 'CLOSEDATE': + case 'createdTime': + case 'updatedTime': + case 'movedTime': + case 'lastActivityTime': if ($this->data[$offset] !== '') { return DateTimeImmutable::createFromFormat(DATE_ATOM, $this->data[$offset]); } return null; + // deal + case 'PRICE_EXCLUSIVE': + case 'PRICE_NETTO': + case 'PRICE_BRUTTO': + case 'PRICE': + 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 'currencyId': + case 'accountCurrencyId': + return new Currency($this->data[$offset]); default: return $this->data[$offset] ?? null; } @@ -113,7 +138,7 @@ public function __get($offset) * @param string $fieldName * * @return mixed|null - * @throws \Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNotFoundException + * @throws UserfieldNotFoundException */ protected function getKeyWithUserfieldByFieldName(string $fieldName) { diff --git a/src/Services/CRM/Item/Result/ItemItemResult.php b/src/Services/CRM/Item/Result/ItemItemResult.php new file mode 100644 index 00000000..3d7090a8 --- /dev/null +++ b/src/Services/CRM/Item/Result/ItemItemResult.php @@ -0,0 +1,53 @@ +getCoreResponse()->getResponseData()->getResult()['item']); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Item/Result/ItemsResult.php b/src/Services/CRM/Item/Result/ItemsResult.php new file mode 100644 index 00000000..978ffc0d --- /dev/null +++ b/src/Services/CRM/Item/Result/ItemsResult.php @@ -0,0 +1,25 @@ +getCoreResponse()->getResponseData()->getResult() as $item) { + $items[] = new ItemItemResult($item); + } + + return $items; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Item/Service/Batch.php b/src/Services/CRM/Item/Service/Batch.php new file mode 100644 index 00000000..14ff222b --- /dev/null +++ b/src/Services/CRM/Item/Service/Batch.php @@ -0,0 +1,68 @@ +batch = $batch; + $this->log = $log; + } + + /** + * Batch list method for crm items + * + * @return Generator + * @throws BaseException + */ + public function list(int $entityTypeId, array $order, array $filter, array $select, ?int $limit = null): Generator + { + $this->log->debug( + 'batchList', + [ + 'entityTypeId' => $entityTypeId, + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'limit' => $limit, + ] + ); + foreach ($this->batch->getTraversableList('crm.item.list', $order, $filter, $select, $limit, ['entityTypeId' => $entityTypeId]) as $key => $value) { + yield $key => new ItemItemResult($value); + } + } + + /** + * Batch adding crm items + * + * @return Generator|ItemItemResult[] + * + * @throws BaseException + */ + public function add(int $entityTypeId, array $items): Generator + { + $rawItems = []; + foreach ($items as $item) { + $rawItems[] = [ + 'entityTypeId' => $entityTypeId, + 'fields' => $item, + ]; + } + foreach ($this->batch->addEntityItems('crm.item.add', $rawItems) as $key => $item) { + yield $key => new ItemItemResult($item->getResult()['item']); + } + } +} \ No newline at end of file diff --git a/src/Services/CRM/Item/Service/Item.php b/src/Services/CRM/Item/Service/Item.php new file mode 100644 index 00000000..f080641e --- /dev/null +++ b/src/Services/CRM/Item/Service/Item.php @@ -0,0 +1,158 @@ +batch = $batch; + } + + /** + * Method creates new SPA item with entityTypeId. + * + * @link https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_add.php + * + * + * @param int $entityTypeId + * @param array $fields + * @return ItemResult + * @throws BaseException + * @throws TransportException + */ + public function add(int $entityTypeId, array $fields): ItemResult + { + return new ItemResult( + $this->core->call( + 'crm.item.add', + [ + 'entityTypeId' => $entityTypeId, + 'fields' => $fields, + ] + ) + ); + } + + /** + * Deletes item with id for SPA with entityTypeId. + * + * @link https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_delete.php + * + * @param int $entityTypeId + * @param int $id + * + * @return DeletedItemResult + * @throws BaseException + * @throws TransportException + */ + public function delete(int $entityTypeId, int $id): DeletedItemResult + { + return new DeletedItemResult( + $this->core->call( + 'crm.item.delete', ['entityTypeId' => $entityTypeId, 'id' => $id] + ) + ); + } + + /** + * Returns the fields data with entityTypeId. + * + * @link https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_fields.php + * + * @param int $entityTypeId + * @return FieldsResult + * @throws BaseException + * @throws TransportException + */ + public function fields(int $entityTypeId): FieldsResult + { + return new FieldsResult($this->core->call('crm.item.fields', ['entityTypeId' => $entityTypeId])); + } + + /** + * Returns item data with id for SPA with entityTypeId. + * + * @link https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_get.php + * + * @throws BaseException + * @throws TransportException + */ + public function get(int $entityTypeId, int $id): ItemResult + { + return new ItemResult($this->core->call('crm.item.get', ['entityTypeId' => $entityTypeId, 'id' => $id])); + } + + /** + * Returns array with SPA items with entityTypeId + * + * @link https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_list.php + * + * @throws BaseException + * @throws TransportException + */ + public function list(int $entityTypeId, array $order, array $filter, array $select, int $startItem = 0): ItemsResult + { + return new ItemsResult( + $this->core->call( + 'crm.item.list', + [ + 'entityTypeId' => $entityTypeId, + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $startItem, + ] + ) + ); + } + + /** + * Updates the specified (existing) item. + * + * @link https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_update.php + * + * @throws BaseException + * @throws TransportException + */ + public function update(int $entityTypeId, int $id, array $fields): UpdatedItemResult + { + return new UpdatedItemResult( + $this->core->call( + 'crm.item.update', + [ + 'entityTypeId' => $entityTypeId, + 'id' => $id, + 'fields' => $fields, + ] + ) + ); + } + + /** + * Count by filter + * + * @throws BaseException + * @throws TransportException + */ + public function countByFilter(int $entityTypeId, array $filter = []): int + { + return $this->list($entityTypeId, [], $filter, ['id'], 1)->getCoreResponse()->getResponseData()->getPagination()->getTotal(); + } +} \ No newline at end of file From 631784914743826ecfd6949e7264f4666fe1f19a Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 14 Aug 2023 00:55:29 +0400 Subject: [PATCH 474/647] add duplicate service and tests Signed-off-by: mesilov --- CHANGELOG.md | 3 +- src/Services/CRM/CRMServiceBuilder.php | 12 +++ .../CRM/Duplicates/Result/DuplicateResult.php | 50 ++++++++++++ .../CRM/Duplicates/Service/Duplicate.php | 47 +++++++++++ .../CRM/Duplicates/Service/EntityType.php | 12 +++ .../CRM/Duplicates/Service/DuplicateTest.php | 80 +++++++++++++++++++ tests/Unit/Stubs/NullBatch.php | 8 +- 7 files changed, 210 insertions(+), 2 deletions(-) create mode 100644 src/Services/CRM/Duplicates/Result/DuplicateResult.php create mode 100644 src/Services/CRM/Duplicates/Service/Duplicate.php create mode 100644 src/Services/CRM/Duplicates/Service/EntityType.php create mode 100644 tests/Integration/Services/CRM/Duplicates/Service/DuplicateTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index dbd28db7..40b2ac1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,8 @@ * `Bitrix24\SDK\Services\User\Service\User::get` - get user * `Bitrix24\SDK\Services\User\Service\User::update` - update user * `Bitrix24\SDK\Services\User\Service\User::search` - search users -* add [crm item support](https://github.com/mesilov/bitrix24-php-sdk/issues/330) +* add [crm item support](https://github.com/mesilov/bitrix24-php-sdk/issues/330) +* add Duplicate search support for `Bitrix24\SDK\Services\CRM\Duplicates\Service\Duplicate` ### Changed diff --git a/src/Services/CRM/CRMServiceBuilder.php b/src/Services/CRM/CRMServiceBuilder.php index f78a34ae..49678877 100644 --- a/src/Services/CRM/CRMServiceBuilder.php +++ b/src/Services/CRM/CRMServiceBuilder.php @@ -183,4 +183,16 @@ public function item(): Item\Service\Item return $this->serviceCache[__METHOD__]; } + + public function duplicate(): Duplicates\Service\Duplicate + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Duplicates\Service\Duplicate( + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } } \ No newline at end of file diff --git a/src/Services/CRM/Duplicates/Result/DuplicateResult.php b/src/Services/CRM/Duplicates/Result/DuplicateResult.php new file mode 100644 index 00000000..dffe44ad --- /dev/null +++ b/src/Services/CRM/Duplicates/Result/DuplicateResult.php @@ -0,0 +1,50 @@ +getCoreResponse()->getResponseData()->getResult())) { + return false; + } + + if (count($this->getCoreResponse()->getResponseData()->getResult()['CONTACT']) > 1) { + return true; + } + + return false; + } + + public function hasOneContact(): bool + { + if (!array_key_exists('CONTACT', $this->getCoreResponse()->getResponseData()->getResult())) { + return false; + } + + if (count($this->getCoreResponse()->getResponseData()->getResult()['CONTACT']) === 1) { + return true; + } + + return false; + } + + /** + * @return array + * @throws BaseException + */ + public function getContactsId(): array + { + if (!array_key_exists('CONTACT', $this->getCoreResponse()->getResponseData()->getResult())) { + return []; + } + + return $this->getCoreResponse()->getResponseData()->getResult()['CONTACT']; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Duplicates/Service/Duplicate.php b/src/Services/CRM/Duplicates/Service/Duplicate.php new file mode 100644 index 00000000..9b0b122d --- /dev/null +++ b/src/Services/CRM/Duplicates/Service/Duplicate.php @@ -0,0 +1,47 @@ + $phones + * @param EntityType|null $entityType + * @return DuplicateResult + * @throws BaseException + * @throws TransportException + */ + public function findByPhone(array $phones, ?EntityType $entityType = null): mixed + { + return new DuplicateResult($this->core->call('crm.duplicate.findbycomm', + [ + 'type' => 'PHONE', + 'values' => $phones, + 'entity_type' => $entityType?->value + ])); + } + + /** + * @param array $emails + * @param EntityType|null $entityType + * @return DuplicateResult + * @throws BaseException + * @throws TransportException + */ + public function findByEmail(array $emails, ?EntityType $entityType = null): DuplicateResult + { + return new DuplicateResult($this->core->call('crm.duplicate.findbycomm', + [ + 'type' => 'EMAIL', + 'values' => $emails, + 'entity_type' => $entityType?->value + ])); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Duplicates/Service/EntityType.php b/src/Services/CRM/Duplicates/Service/EntityType.php new file mode 100644 index 00000000..3e5583ea --- /dev/null +++ b/src/Services/CRM/Duplicates/Service/EntityType.php @@ -0,0 +1,12 @@ +duplicate->findByEmail([sprintf('%s@gmail.com', time())]); + $this->assertFalse($res->hasDuplicateContacts()); + $this->assertFalse($res->hasOneContact()); + $this->assertCount(0, $res->getContactsId()); + } + + /** + * @return void + * @throws BaseException + * @throws TransportException + * @covers \Bitrix24\SDK\Services\CRM\Duplicates\Service\Duplicate::findByEmail + */ + public function testDuplicatesByEmailOneItemFound(): void + { + $email = sprintf('%s@gmail.com', time()); + $b24ContactId = $this->contactService->add([ + 'NAME' => 'Test', + 'LAST_NAME' => 'Test', + 'EMAIL' => [ + [ + 'VALUE' => $email, + 'TYPE' => 'WORK' + ] + ] + ])->getId(); + + $res = $this->duplicate->findByEmail([$email]); + $this->assertFalse($res->hasDuplicateContacts()); + $this->assertTrue($res->hasOneContact()); + $this->assertCount(1, $res->getContactsId()); + } + + /** + * @return void + * @throws BaseException + * @throws TransportException + * @covers \Bitrix24\SDK\Services\CRM\Duplicates\Service\Duplicate::findByPhone + */ + public function testDuplicatesByPhoneNotFound(): void + { + $res = $this->duplicate->findByPhone([sprintf('+1%s', time())]); + $this->assertFalse($res->hasDuplicateContacts()); + $this->assertFalse($res->hasOneContact()); + $this->assertCount(0, $res->getContactsId()); + } + + + public function setUp(): void + { + $this->contactService = Fabric::getServiceBuilder()->getCRMScope()->contact(); + $this->duplicate = Fabric::getServiceBuilder()->getCRMScope()->duplicate(); + + } +} \ No newline at end of file diff --git a/tests/Unit/Stubs/NullBatch.php b/tests/Unit/Stubs/NullBatch.php index f775dab6..7781fa6f 100644 --- a/tests/Unit/Stubs/NullBatch.php +++ b/tests/Unit/Stubs/NullBatch.php @@ -18,9 +18,15 @@ 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): Generator + public function getTraversableList(string $apiMethod, array $order, array $filter, array $select, ?int $limit = null, ?array $additionalParameters = null): Generator { yield []; } From 97c833fa58339c32f924a44f2599babfd92d136c Mon Sep 17 00:00:00 2001 From: mesilov Date: Tue, 22 Aug 2023 01:52:22 +0400 Subject: [PATCH 475/647] add cli util - copy property values Signed-off-by: mesilov --- bin/console | 2 + tools/Commands/CopyPropertyValues.php | 296 ++++++++++++++++++++++++++ 2 files changed, 298 insertions(+) create mode 100644 tools/Commands/CopyPropertyValues.php diff --git a/bin/console b/bin/console index 86ccde03..5a561cd4 100644 --- a/bin/console +++ b/bin/console @@ -1,6 +1,7 @@ #!/usr/bin/env php add(new GenerateContactsCommand($log)); $application->add(new ListCommand($log)); $application->add(new ShowFieldsDescriptionCommand($log)); +$application->add(new CopyPropertyValues($log)); $application->run($input); \ No newline at end of file diff --git a/tools/Commands/CopyPropertyValues.php b/tools/Commands/CopyPropertyValues.php new file mode 100644 index 00000000..d4cd9d8c --- /dev/null +++ b/tools/Commands/CopyPropertyValues.php @@ -0,0 +1,296 @@ +logger = $logger; + parent::__construct(); + } + + /** + * @param OutputInterface $output + * @param Contact $service + * @param array $updateCmd + * @return void + * @throws BaseException + */ + public function updateItems(OutputInterface $output, Contact $service, array $updateCmd): void + { + $progressBar = new ProgressBar($output, count($updateCmd)); + $progressBar->start(); + + foreach ($service->batch->update($updateCmd) as $item) { + $this->logger->debug('updateItems', [ + 'isUpdated' => $item->isSuccess() === true ? 'Y' : 'N', + ]); + $progressBar->advance(); + } + + $progressBar->finish(); + } + + + public function createUpdateCommand(array $data, string $b24SourceProp, string $b24DestinationProp): array + { + $updateCmd = []; + foreach ($data as $id => $item) { + $updateCmd[$id] = [ + 'fields' => [ + $b24DestinationProp =>$item[$b24SourceProp], + ] + ]; + } + + return $updateCmd; + } + + /** + * @param OutputInterface $output + * @param Contact $service + * @param array $filter + * @param string $b24SourceProp + * @param string $b24DestinationProp + * @return array + * @throws BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNotFoundException + */ + public function readDataFromProperties(OutputInterface $output, Contact $service, array $filter, string $b24SourceProp, string $b24DestinationProp): array + { + $progressBar = new ProgressBar($output, $service->countByFilter($filter)); + $progressBar->start(); + + $data = []; + foreach ($service->batch->list([], $filter, ['ID', $b24SourceProp, $b24DestinationProp]) as $id => $item) { + $data[$item->ID] = [ + $b24SourceProp => (string)$item->getUserfieldByFieldName($b24SourceProp), + $b24DestinationProp => (string)$item->getUserfieldByFieldName($b24DestinationProp), + ]; + $progressBar->advance(); + } + $progressBar->finish(); + + return $data; + } + + protected function configure(): void + { + $this + ->setDescription('copy property values from one property to another') + ->setHelp('copy property values from one property to another in same portal') + ->addOption( + self::WEBHOOK_URL, + null, + InputOption::VALUE_REQUIRED, + 'bitrix24 incoming webhook', + '' + ) + ->addOption( + self::SOURCE_PROPERTY, + null, + InputOption::VALUE_REQUIRED, + 'source property id', + + ) + ->addOption( + self::DESTINATION_PROPERTY, + null, + InputOption::VALUE_REQUIRED, + 'destination property id', + ) + ->addOption( + self::ENTITY_TYPE_PROPERTY, + null, + InputOption::VALUE_REQUIRED, + 'entity type: contact, company, lead, deal', + ); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $this->logger->debug('CopyPropertyValues.start'); + + $b24Webhook = (string)$input->getOption(self::WEBHOOK_URL); + $b24EntityType = (string)$input->getOption(self::ENTITY_TYPE_PROPERTY); + $b24SourceProp = (string)$input->getOption(self::SOURCE_PROPERTY); + $b24DestinationProp = (string)$input->getOption(self::DESTINATION_PROPERTY); + + $io = new SymfonyStyle($input, $output); + $output->writeln( + [ + 'Copy property values from one property to another', + '========================', + sprintf('webhook url: %s', $b24Webhook), + sprintf('entity type: %s', $b24EntityType), + sprintf('source property: %s', $b24SourceProp), + sprintf('destination property: %s', $b24DestinationProp), + ] + ); + + try { + if ($b24Webhook === '') { + throw new InvalidArgumentException('webhook url is empty'); + } + if ($b24EntityType === '') { + throw new InvalidArgumentException('entity_type is empty'); + } + if ($b24SourceProp === '') { + throw new InvalidArgumentException('source property is empty'); + } + if ($b24DestinationProp === '') { + throw new InvalidArgumentException('destination property is empty'); + } + $sb = (new ServiceBuilderFactory(new EventDispatcher(), $this->logger))->initFromWebhook($b24Webhook); + if (!in_array($b24EntityType, $this->supportedEntityTypes, true)) { + throw new InvalidArgumentException(sprintf('entity type %s is not supported', $b24EntityType)); + } + + $service = null; + switch ($b24EntityType) { + case 'contact': + $fields = $sb->getCRMScope()->contact()->fields(); + $service = $sb->getCRMScope()->contact(); + break; + case 'company': + case 'lead': + case 'deal': + default: + throw new InvalidArgumentException(sprintf('unsupported entity type %s', $b24EntityType)); + } + + if (!array_key_exists($b24SourceProp, $fields->getFieldsDescription())) { + throw new InvalidArgumentException(sprintf('source property «%s» is not found in entity %s', $b24SourceProp, $b24EntityType)); + } + if (!array_key_exists($b24DestinationProp, $fields->getFieldsDescription())) { + throw new InvalidArgumentException(sprintf('destination property «%s» is not found in entity %s', $b24DestinationProp, $b24EntityType)); + } + + // количество элементов c заполненным полем источником + // количество элементов с заполненным полем назначения + // количество элементов у которых заполнено ОБА поля + $totalElementsCnt = $service->countByFilter(); + $elementsWithFilledSourceProp = $service->countByFilter([sprintf('!%s', $b24SourceProp) => null]); + $elementsWithoutFilledSourceProp = $service->countByFilter([sprintf('%s', $b24SourceProp) => null]); + $elementsWithFilledDestinationProp = $service->countByFilter([sprintf('!%s', $b24DestinationProp) => null]); + $elementsWithoutFilledDestinationProp = $service->countByFilter([sprintf('%s', $b24DestinationProp) => null]); + + $io->info( + [ + '', + sprintf('total elements count: %s ', $totalElementsCnt), + sprintf('elements with filled source property: %s ', $elementsWithFilledSourceProp), + sprintf('elements without filled source property: %s ', $elementsWithoutFilledSourceProp), + sprintf('elements with filled destination property: %s ', $elementsWithFilledDestinationProp), + sprintf('elements without filled destination property: %s ', $elementsWithoutFilledDestinationProp) + ] + ); + $io->info('read data from bitrix24...'); + // read data from source and destinations properties + $dataFromProperties = $this->readDataFromProperties($output, $service, [ + sprintf('!%s', $b24SourceProp) => '' + ], $b24SourceProp, $b24DestinationProp); + + // exclude items with filled destination property + $dataToCopy = []; + $conflictData = []; + foreach ($dataFromProperties as $id => $item) { + // pass items with copied values + if ($item[$b24SourceProp] === $item[$b24DestinationProp]) { + continue; + } + + // filter conflict items + if($item[$b24DestinationProp] !== '') { + $conflictData[$id] = $item; + } + // filter items to copy + if($item[$b24DestinationProp] === '') { + $dataToCopy[$id] = $item; + } + } + $io->newLine(); + $io->warning([ + '', + sprintf('conflict items count: %s', count($conflictData)), + sprintf('problem id: %s', implode(', ', array_keys($conflictData))), + ]); + + $io->info([ + '', + sprintf('items to copy count: %s', count($dataToCopy)) + ]); + + // build update command + $updateCmd = $this->createUpdateCommand($dataToCopy, $b24SourceProp, $b24DestinationProp); + + // update items + $this->updateItems($output, $service, $updateCmd); + + $io->success('all items updated'); + } catch (BaseException $exception) { + $io = new SymfonyStyle($input, $output); + $io->caution(sprintf('error message: %s', $exception->getMessage())); + $io->text( + $exception->getTraceAsString() + ); + } catch (\Throwable $exception) { + $io = new SymfonyStyle($input, $output); + $io->caution('unknown error'); + $io->text( + [ + sprintf('%s', $exception->getMessage()), + ] + ); + } + $this->logger->debug('CopyPropertyValues.finish'); + + return Command::SUCCESS; + } +} \ No newline at end of file From 8f144c9aa30b8ac8f7f4b60b0dde81563b80448a Mon Sep 17 00:00:00 2001 From: mesilov Date: Tue, 22 Aug 2023 01:52:54 +0400 Subject: [PATCH 476/647] fix operating error on boxes Signed-off-by: mesilov --- src/Core/Response/DTO/Time.php | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/Core/Response/DTO/Time.php b/src/Core/Response/DTO/Time.php index e1302aa1..3e83f84b 100644 --- a/src/Core/Response/DTO/Time.php +++ b/src/Core/Response/DTO/Time.php @@ -33,25 +33,26 @@ class Time /** * Time constructor. * - * @param float $start - * @param float $finish - * @param float $duration - * @param float $processing - * @param float $operating + * @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 + * @param int|null $operatingResetAt */ public function __construct( - float $start, - float $finish, - float $duration, - float $processing, - float $operating, + float $start, + float $finish, + float $duration, + float $processing, + float $operating, DateTimeImmutable $dateStart, DateTimeImmutable $dateFinish, - ?int $operatingResetAt - ) { + ?int $operatingResetAt + ) + { $this->start = $start; $this->finish = $finish; $this->duration = $duration; @@ -139,7 +140,7 @@ public static function initFromResponse(array $response): self (float)$response['finish'], (float)$response['duration'], (float)$response['processing'], - (float)$response['operating'], + array_key_exists('operating', $response) ? (float)$response['operating'] : 0, new DateTimeImmutable($response['date_start']), new DateTimeImmutable($response['date_finish']), $response['operating_reset_at'] ?? null From e13f9214a6601d45a5feb1ef9b6d75cd0a8d51dd Mon Sep 17 00:00:00 2001 From: mesilov Date: Tue, 22 Aug 2023 01:54:29 +0400 Subject: [PATCH 477/647] fix errors on items tests Signed-off-by: mesilov --- src/Core/Batch.php | 2 +- src/Core/CoreBuilder.php | 23 ++++++------------- .../CRM/Common/Result/AbstractCrmItem.php | 4 +++- 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/src/Core/Batch.php b/src/Core/Batch.php index 4c30f8c7..e647b904 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -210,7 +210,7 @@ public function updateEntityItems(string $apiMethod, array $entityItems): Genera $this->registerCommand($apiMethod, [ 'id' => $entityItemId, 'fields' => $entityItem['fields'], - 'params' => $entityItem['params'], + 'params' => $entityItem['params'] ?? null, ]); } diff --git a/src/Core/CoreBuilder.php b/src/Core/CoreBuilder.php index e188ae62..8e5b99d8 100644 --- a/src/Core/CoreBuilder.php +++ b/src/Core/CoreBuilder.php @@ -60,11 +60,6 @@ public function withCredentials(Credentials $credentials): self return $this; } - /** - * @param ApiClientInterface $apiClient - * - * @return $this - */ public function withApiClient(ApiClientInterface $apiClient): self { $this->apiClient = $apiClient; @@ -72,11 +67,13 @@ public function withApiClient(ApiClientInterface $apiClient): self return $this; } - /** - * @param LoggerInterface $logger - * - * @return $this - */ + public function withHttpClient(HttpClientInterface $httpClient):self + { + $this->httpClient = $httpClient; + + return $this; + } + public function withLogger(LoggerInterface $logger): self { $this->logger = $logger; @@ -84,11 +81,6 @@ public function withLogger(LoggerInterface $logger): self return $this; } - /** - * @param EventDispatcherInterface $eventDispatcher - * - * @return $this - */ public function withEventDispatcher(EventDispatcherInterface $eventDispatcher): self { $this->eventDispatcher = $eventDispatcher; @@ -97,7 +89,6 @@ public function withEventDispatcher(EventDispatcherInterface $eventDispatcher): } /** - * @return CoreInterface * @throws InvalidArgumentException */ public function build(): CoreInterface diff --git a/src/Services/CRM/Common/Result/AbstractCrmItem.php b/src/Services/CRM/Common/Result/AbstractCrmItem.php index 81467927..b8670f54 100644 --- a/src/Services/CRM/Common/Result/AbstractCrmItem.php +++ b/src/Services/CRM/Common/Result/AbstractCrmItem.php @@ -142,7 +142,9 @@ public function __get($offset) */ protected function getKeyWithUserfieldByFieldName(string $fieldName) { - $fieldName = self::CRM_USERFIELD_PREFIX . $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)); } From ccf72f1228c672e9404fdbbf4abed0d2432a3e75 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 24 Aug 2023 01:46:27 +0400 Subject: [PATCH 478/647] change interface Bitrix24AccountInterface signature Signed-off-by: mesilov --- CHANGELOG.md | 10 +++ .../Bitrix24AccountInterface.php | 67 ++++++++++++++----- 2 files changed, 62 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 40b2ac1b..d2284a5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,16 @@ to `Bitrix24\SDK\Services\Telephony\Requests\Events\OnExternalCallStart\OnExternalCallStart` * from `Bitrix24\SDK\Services\Telephony\Requests\Events\OnVoximplantCallEnd` to `Bitrix24\SDK\Services\Telephony\Requests\Events\OnVoximplantCallEnd\OnVoximplantCallEnd` +* ❗Changes in `Bitrix24\SDK\Application\Contracts\Bitrix24Account\Bitrix24AccountInterface`: + * method `getContactPerson` renamed to `getContactPersonId` + * added method `getApplicationVersion` + * added method `updateApplicationVersion` + * added method `getApplicationScope` + * added method `applicationInstalled` + * added method `applicationUninstalled` + * added method `markAccountAsDeactivated` + * removed method `markAccountAsDeleted` + * changed method `markAccountAsActive` signature ### Bugfix diff --git a/src/Application/Contracts/Bitrix24Account/Bitrix24AccountInterface.php b/src/Application/Contracts/Bitrix24Account/Bitrix24AccountInterface.php index dcde72d7..f57e0f58 100644 --- a/src/Application/Contracts/Bitrix24Account/Bitrix24AccountInterface.php +++ b/src/Application/Contracts/Bitrix24Account/Bitrix24AccountInterface.php @@ -4,69 +4,106 @@ namespace Bitrix24\SDK\Application\Contracts\Bitrix24Account; +use Bitrix24\SDK\Core\Credentials\Scope; use Symfony\Component\Uid\Uuid; use Bitrix24\SDK\Core\Response\DTO\RenewedAccessToken; interface Bitrix24AccountInterface { /** - * @return \Symfony\Component\Uid\Uuid + * @return Uuid */ public function getId(): Uuid; + /** - * @return \Symfony\Component\Uid\Uuid + * @return Uuid */ - public function getContactPerson(): Uuid; + public function getContactPersonId(): Uuid; + /** * @return string */ public function getMemberId(): string; + /** * @return string */ public function getDomainUrl(): string; + /** * @return Bitrix24AccountStatus */ public function getStatus(): Bitrix24AccountStatus; + /** * @return string */ public function getAccessToken(): string; + /** * @return string */ public function getRefreshToken(): string; + /** * @return int */ public function getExpires(): int; + /** - * @param \Bitrix24\SDK\Core\Response\DTO\RenewedAccessToken $renewedAccessToken + * Get application version * - * @return void + * @return int */ - public function renewAccessToken(RenewedAccessToken $renewedAccessToken): void; + public function getApplicationVersion(): int; + /** - * @param string $newDomainUrl + * Update application version if application was updated in marketplace * + * @param int $version + * @param Scope|null $newScope * @return void */ - public function changeDomainUrl(string $newDomainUrl): void; + public function updateApplicationVersion(int $version, ?Scope $newScope): void; + /** - * Switch account to Active status - installation is finalized + * Get application scope (permissions) * - * @param string $applicationToken + * @return Scope + */ + public function getApplicationScope(): Scope; + + /** + * @param RenewedAccessToken $renewedAccessToken * * @return void */ - public function markAccountAsActive(string $applicationToken): void; + public function renewAccessToken(RenewedAccessToken $renewedAccessToken): void; + /** - * Change account status to Deleted - * - * @param string $applicationToken + * @param string $newDomainUrl * * @return void */ - public function markAccountAsDeleted(string $applicationToken): void; + public function changeDomainUrl(string $newDomainUrl): void; + + /** + * Application installed on portal and finish installation flow + */ + public function applicationInstalled(string $applicationToken): void; + + /** + * Application uninstalled from portal + */ + public function applicationUninstalled(string $applicationToken): void; + + /** + * Switch account to Active status + */ + public function markAccountAsActive(): void; + + /** + * Change account status to Deactivated + */ + public function markAccountAsDeactivated(): void; } \ No newline at end of file From b2349539411828209c9d4412d9aec9673727aa37 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 27 Aug 2023 00:49:04 +0400 Subject: [PATCH 479/647] add bitrix24 user id Signed-off-by: mesilov --- CHANGELOG.md | 1 + .../Contracts/Bitrix24Account/Bitrix24AccountInterface.php | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2284a5f..4f62f651 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,7 @@ * added method `applicationInstalled` * added method `applicationUninstalled` * added method `markAccountAsDeactivated` + * added method `getBitrix24UserId` * removed method `markAccountAsDeleted` * changed method `markAccountAsActive` signature diff --git a/src/Application/Contracts/Bitrix24Account/Bitrix24AccountInterface.php b/src/Application/Contracts/Bitrix24Account/Bitrix24AccountInterface.php index f57e0f58..6c5109a1 100644 --- a/src/Application/Contracts/Bitrix24Account/Bitrix24AccountInterface.php +++ b/src/Application/Contracts/Bitrix24Account/Bitrix24AccountInterface.php @@ -106,4 +106,9 @@ public function markAccountAsActive(): void; * Change account status to Deactivated */ public function markAccountAsDeactivated(): void; + + /** + * Get Bitrix24 user id who installed application and own this account + */ + public function getBitrix24UserId(): int; } \ No newline at end of file From d2a8a89fdc3846f57316d8dcb939f59fbdfd6e57 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 28 Aug 2023 21:55:54 +0400 Subject: [PATCH 480/647] change signatures in application contracts Signed-off-by: mesilov --- CHANGELOG.md | 13 ++++- .../Bitrix24AccountInterface.php | 4 +- .../Bitrix24AccountRepositoryInterface.php | 50 ++++++------------- 3 files changed, 29 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f62f651..ef1eab2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,10 +41,19 @@ * added method `getApplicationScope` * added method `applicationInstalled` * added method `applicationUninstalled` - * added method `markAccountAsDeactivated` + * added method `markAsDeactivated` * added method `getBitrix24UserId` * removed method `markAccountAsDeleted` - * changed method `markAccountAsActive` signature + * changed method `markAsActive` +* ❗Changes in `Bitrix24\SDK\Application\Contracts\Bitrix24Account\Bitrix24AccountRepositoryInterface`: + * method `saveAccount` renamed to `save` + * method `deleteAccount` renamed to `delete` + * method `findAccountByMemberId` renamed to `findByMemberId` + * method `getAccountByMemberId` renamed to `getByMemberId` + * method `findAccountByContactPersonId` renamed to `findByContactPersonId` + * method `findAccountByDomainUrl` renamed to `findByDomainUrl` + * add method `findAllActive` + * add method `findAllDeactivated` ### Bugfix diff --git a/src/Application/Contracts/Bitrix24Account/Bitrix24AccountInterface.php b/src/Application/Contracts/Bitrix24Account/Bitrix24AccountInterface.php index 6c5109a1..654f377b 100644 --- a/src/Application/Contracts/Bitrix24Account/Bitrix24AccountInterface.php +++ b/src/Application/Contracts/Bitrix24Account/Bitrix24AccountInterface.php @@ -100,12 +100,12 @@ public function applicationUninstalled(string $applicationToken): void; /** * Switch account to Active status */ - public function markAccountAsActive(): void; + public function markAsActive(): void; /** * Change account status to Deactivated */ - public function markAccountAsDeactivated(): void; + public function markAsDeactivated(): void; /** * Get Bitrix24 user id who installed application and own this account diff --git a/src/Application/Contracts/Bitrix24Account/Bitrix24AccountRepositoryInterface.php b/src/Application/Contracts/Bitrix24Account/Bitrix24AccountRepositoryInterface.php index deeae92e..980b7e3a 100644 --- a/src/Application/Contracts/Bitrix24Account/Bitrix24AccountRepositoryInterface.php +++ b/src/Application/Contracts/Bitrix24Account/Bitrix24AccountRepositoryInterface.php @@ -10,64 +10,46 @@ interface Bitrix24AccountRepositoryInterface { /** * Save account - * - * @param Bitrix24AccountInterface $entity - * @param bool $flush - * - * @return void */ - public function saveAccount(Bitrix24AccountInterface $entity, bool $flush = false): void; + public function save(Bitrix24AccountInterface $entity, bool $flush = false): void; /** * Get by account id - * - * @param \Symfony\Component\Uid\Uuid $id - * - * @return Bitrix24AccountInterface */ public function getById(Uuid $id): Bitrix24AccountInterface; /** * Delete account - * - * @param Bitrix24AccountInterface $entity - * @param bool $flush - * - * @return void */ - public function deleteAccount(Bitrix24AccountInterface $entity, bool $flush = false): void; + public function delete(Bitrix24AccountInterface $entity, bool $flush = false): void; /** * Find account by member_id - * - * @return ?Bitrix24AccountInterface Returns an array of Bitrix24Account objects */ - public function findAccountByMemberId(string $memberId): ?Bitrix24AccountInterface; + public function findByMemberId(string $memberId): ?Bitrix24AccountInterface; /** * Get account by member_id - * - * @param string $memberId - * - * @return Bitrix24AccountInterface */ - public function getAccountByMemberId(string $memberId): Bitrix24AccountInterface; + public function getByMemberId(string $memberId): Bitrix24AccountInterface; /** * Find account by contact person id - person, who installed application - * - * @param \Symfony\Component\Uid\Uuid $contactPersonId - * - * @return Bitrix24AccountInterface|null */ - public function findAccountByContactPersonId(Uuid $contactPersonId): ?Bitrix24AccountInterface; + public function findByContactPersonId(Uuid $contactPersonId): ?Bitrix24AccountInterface; /** * Find account by domain url - * - * @param string $domainUrl - * - * @return Bitrix24AccountInterface|null */ - public function findAccountByDomainUrl(string $domainUrl): ?Bitrix24AccountInterface; + public function findByDomainUrl(string $domainUrl): ?Bitrix24AccountInterface; + + /** + * @return array + */ + public function findAllActive(): array; + + /** + * @return array + */ + public function findAllDeactivated(): array; } \ No newline at end of file From 6884661e51d9268cd7c38e7a123dbc12d88559e7 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 7 Sep 2023 02:27:06 +0400 Subject: [PATCH 481/647] add deal stage semantic id Signed-off-by: mesilov --- CHANGELOG.md | 1 + src/Services/CRM/Deal/DealStageSemanticId.php | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 src/Services/CRM/Deal/DealStageSemanticId.php diff --git a/CHANGELOG.md b/CHANGELOG.md index ef1eab2b..39555077 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ * `Bitrix24\SDK\Services\User\Service\User::update` - update user * `Bitrix24\SDK\Services\User\Service\User::search` - search users * 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` ### Changed diff --git a/src/Services/CRM/Deal/DealStageSemanticId.php b/src/Services/CRM/Deal/DealStageSemanticId.php new file mode 100644 index 00000000..e591b956 --- /dev/null +++ b/src/Services/CRM/Deal/DealStageSemanticId.php @@ -0,0 +1,18 @@ + Date: Sat, 9 Sep 2023 02:03:05 +0400 Subject: [PATCH 482/647] fix errors for scope Signed-off-by: mesilov --- CHANGELOG.md | 1 + src/Core/Credentials/Scope.php | 16 +++++------ .../Credentials/ApplicationProfileTest.php | 28 ++++++++++++------- tests/Unit/Core/Credentials/ScopeTest.php | 9 ++++++ 4 files changed, 36 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 39555077..a8138f8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,6 +64,7 @@ * 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 ### etc * move CLI entry point to `bin/console` diff --git a/src/Core/Credentials/Scope.php b/src/Core/Credentials/Scope.php index 6e64d1aa..d028e1e7 100644 --- a/src/Core/Credentials/Scope.php +++ b/src/Core/Credentials/Scope.php @@ -6,11 +6,6 @@ use Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException; -/** - * Class Scope - * - * @package Bitrix24\SDK\Core\Credentials - */ class Scope { /** @@ -84,9 +79,14 @@ class Scope public function __construct(array $scope = []) { $scope = array_unique(array_map('strtolower', $scope)); - foreach ($scope as $item) { - if (!in_array($item, $this->availableScope, true)) { - throw new UnknownScopeCodeException(sprintf('unknown application scope code - %s', $item)); + + if (count($scope) === 1 && $scope[0] === '') { + $scope = []; + } else { + foreach ($scope as $item) { + if (!in_array($item, $this->availableScope, true)) { + throw new UnknownScopeCodeException(sprintf('unknown application scope code - %s', $item)); + } } } diff --git a/tests/Unit/Core/Credentials/ApplicationProfileTest.php b/tests/Unit/Core/Credentials/ApplicationProfileTest.php index a66a38ce..17956aac 100644 --- a/tests/Unit/Core/Credentials/ApplicationProfileTest.php +++ b/tests/Unit/Core/Credentials/ApplicationProfileTest.php @@ -13,11 +13,11 @@ class ApplicationProfileTest extends TestCase { /** * - * @param array $arr + * @param array $arr * @param string|null $expectedException * * @return void - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @throws InvalidArgumentException * @dataProvider arrayDataProvider */ public function testFromArray(array $arr, ?string $expectedException): void @@ -35,35 +35,43 @@ public function arrayDataProvider(): Generator { yield 'valid' => [ [ - 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID' => '1', + 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID' => '1', 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET' => '2', - 'BITRIX24_PHP_SDK_APPLICATION_SCOPE' => 'user', + 'BITRIX24_PHP_SDK_APPLICATION_SCOPE' => 'user', ], null, ]; yield 'without client id' => [ [ - '' => '1', + '' => '1', 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET' => '2', - 'BITRIX24_PHP_SDK_APPLICATION_SCOPE' => 'user', + 'BITRIX24_PHP_SDK_APPLICATION_SCOPE' => 'user', ], InvalidArgumentException::class, ]; yield 'without client secret' => [ [ 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID' => '1', - '' => '2', - 'BITRIX24_PHP_SDK_APPLICATION_SCOPE' => 'user', + '' => '2', + 'BITRIX24_PHP_SDK_APPLICATION_SCOPE' => 'user', ], InvalidArgumentException::class, ]; yield 'without client application scope' => [ [ - 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID' => '1', + 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID' => '1', 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET' => '2', - '' => 'user', + '' => 'user', ], InvalidArgumentException::class, ]; + yield 'with empty scope' => [ + [ + 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID' => '1', + 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET' => '2', + 'BITRIX24_PHP_SDK_APPLICATION_SCOPE' => '', + ], + null + ]; } } diff --git a/tests/Unit/Core/Credentials/ScopeTest.php b/tests/Unit/Core/Credentials/ScopeTest.php index d7d37b32..e974fd36 100644 --- a/tests/Unit/Core/Credentials/ScopeTest.php +++ b/tests/Unit/Core/Credentials/ScopeTest.php @@ -73,6 +73,15 @@ public function testUnknownScope(): void $scope = new Scope(['fooo']); } + /** + * @throws UnknownScopeCodeException + */ + public function testEmptyScope(): void + { + $scope = new Scope(['']); + $this->assertEquals([], $scope->getScopeCodes()); + } + /** * @throws UnknownScopeCodeException */ From eb1f34a7b0b6b8f3eff4d0aea503a69284a24232 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 9 Sep 2023 02:34:53 +0400 Subject: [PATCH 483/647] fix errors for Core Signed-off-by: mesilov --- CHANGELOG.md | 3 ++- src/Core/Core.php | 10 ++++++++++ .../Exceptions/AuthForbiddenException.php | 9 +++++++++ tests/Integration/Core/CoreTest.php | 19 +++++++++++++++++++ 4 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 src/Core/Exceptions/AuthForbiddenException.php diff --git a/CHANGELOG.md b/CHANGELOG.md index a8138f8d..81ff9ad6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,7 +64,8 @@ * fix [add helper metods isError for registerCallResult fortelephony](https://github.com/mesilov/bitrix24-php-sdk/issues/335) * fix [add return type for crm multifields phone, email, im](https://github.com/mesilov/bitrix24-php-sdk/issues/338) * fix errors in `ShowFieldsDescriptionCommand` metadata reader CLI command -* fix errors for `ApplicationProfile` with empty scope +* fix errors for `ApplicationProfile` with empty scope +* fix errors in `Core` with auth attempt to non-exists portal ### etc * move CLI entry point to `bin/console` diff --git a/src/Core/Core.php b/src/Core/Core.php index a739fe9a..73511395 100644 --- a/src/Core/Core.php +++ b/src/Core/Core.php @@ -7,6 +7,7 @@ use Bitrix24\SDK\Core\Commands\Command; use Bitrix24\SDK\Core\Contracts\ApiClientInterface; use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Exceptions\AuthForbiddenException; use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Exceptions\TransportException; use Bitrix24\SDK\Core\Response\Response; @@ -146,6 +147,15 @@ public function call(string $apiMethod, array $parameters = []): Response throw new BaseException('UNAUTHORIZED request error'); } break; + case StatusCodeInterface::STATUS_FORBIDDEN: + $this->logger->warning( + 'bitrix24 portal authorisation forbidden', + [ + 'apiMethod' => $apiMethod, + 'b24DomainUrl' => $this->apiClient->getCredentials()->getDomainUrl(), + ] + ); + throw new AuthForbiddenException(sprintf('authorisation forbidden for portal %s ', $this->apiClient->getCredentials()->getDomainUrl())); case StatusCodeInterface::STATUS_SERVICE_UNAVAILABLE: $body = $apiCallResponse->toArray(false); $this->logger->notice( diff --git a/src/Core/Exceptions/AuthForbiddenException.php b/src/Core/Exceptions/AuthForbiddenException.php new file mode 100644 index 00000000..2d444876 --- /dev/null +++ b/src/Core/Exceptions/AuthForbiddenException.php @@ -0,0 +1,9 @@ +assertIsArray($response->getResponseData()->getResult()); } + public function testConnectToNonExistsBitrix24PortalInCloud():void + { + $core = (new CoreBuilder()) + ->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); + $core->call('app.info'); + } + /** * @return void * @throws \Bitrix24\SDK\Core\Exceptions\BaseException From 50cf106d811a2746c37b988b0727253707141a43 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 25 Nov 2023 01:36:35 +0600 Subject: [PATCH 484/647] add new line in changelog Signed-off-by: mesilov --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81ff9ad6..2c93216c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ * 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) ### Changed From 352e46d4535ab8305a9616faf446d3c3a1e104f3 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 25 Nov 2023 11:32:56 +0600 Subject: [PATCH 485/647] add request id generator proto Signed-off-by: mesilov --- src/Core/ApiClient.php | 46 +++++++++++++++---- src/Core/CoreBuilder.php | 22 ++++++--- .../RequestId/DefaultRequestIdGenerator.php | 22 +++++++++ .../RequestId/RequestIdGeneratorInterface.php | 12 +++++ tests/Unit/Stubs/NullCore.php | 12 ++--- 5 files changed, 93 insertions(+), 21 deletions(-) create mode 100644 src/Infrastructure/HttpClient/RequestId/DefaultRequestIdGenerator.php create mode 100644 src/Infrastructure/HttpClient/RequestId/RequestIdGeneratorInterface.php diff --git a/src/Core/ApiClient.php b/src/Core/ApiClient.php index ac7387e0..9f2f6125 100644 --- a/src/Core/ApiClient.php +++ b/src/Core/ApiClient.php @@ -5,9 +5,11 @@ namespace Bitrix24\SDK\Core; use Bitrix24\SDK\Core\Contracts\ApiClientInterface; +use Bitrix24\SDK\Core\Credentials\Credentials; use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; use Bitrix24\SDK\Core\Exceptions\TransportException; use Bitrix24\SDK\Core\Response\DTO\RenewedAccessToken; +use Bitrix24\SDK\Infrastructure\HttpClient\RequestId\RequestIdGeneratorInterface; use Fig\Http\Message\StatusCodeInterface; use Psr\Log\LoggerInterface; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; @@ -18,7 +20,8 @@ class ApiClient implements ApiClientInterface { protected HttpClientInterface $client; protected LoggerInterface $logger; - protected Credentials\Credentials $credentials; + protected Credentials $credentials; + protected RequestIdGeneratorInterface $requestIdGenerator; /** * @const string */ @@ -32,14 +35,20 @@ class ApiClient implements ApiClientInterface /** * ApiClient constructor. * - * @param Credentials\Credentials $credentials + * @param Credentials $credentials * @param HttpClientInterface $client + * @param RequestIdGeneratorInterface $requestIdGenerator * @param LoggerInterface $logger */ - public function __construct(Credentials\Credentials $credentials, HttpClientInterface $client, LoggerInterface $logger) + public function __construct( + Credentials $credentials, + HttpClientInterface $client, + RequestIdGeneratorInterface $requestIdGenerator, + LoggerInterface $logger) { $this->credentials = $credentials; $this->client = $client; + $this->requestIdGenerator = $requestIdGenerator; $this->logger = $logger; $this->logger->debug( 'ApiClient.init', @@ -64,9 +73,9 @@ protected function getDefaultHeaders(): array } /** - * @return Credentials\Credentials + * @return Credentials */ - public function getCredentials(): Credentials\Credentials + public function getCredentials(): Credentials { return $this->credentials; } @@ -80,7 +89,10 @@ public function getCredentials(): Credentials\Credentials */ public function getNewAccessToken(): RenewedAccessToken { - $this->logger->debug('getNewAccessToken.start'); + $requestId = $this->requestIdGenerator->getRequestId(); + $this->logger->debug('getNewAccessToken.start', [ + 'requestId' => $requestId + ]); if ($this->getCredentials()->getApplicationProfile() === null) { throw new InvalidArgumentException('application profile not set'); } @@ -103,14 +115,21 @@ public function getNewAccessToken(): RenewedAccessToken ); $requestOptions = [ - 'headers' => $this->getDefaultHeaders(), + 'headers' => array_merge( + $this->getDefaultHeaders(), + [ + $this->requestIdGenerator->getHeaderFieldName() => $requestId + ] + ), ]; $response = $this->client->request($method, $url, $requestOptions); $responseData = $response->toArray(false); if ($response->getStatusCode() === StatusCodeInterface::STATUS_OK) { $newAccessToken = RenewedAccessToken::initFromArray($responseData); - $this->logger->debug('getNewAccessToken.finish'); + $this->logger->debug('getNewAccessToken.finish', [ + 'requestId' => $requestId + ]); return $newAccessToken; } if ($response->getStatusCode() === StatusCodeInterface::STATUS_BAD_REQUEST) { @@ -129,12 +148,14 @@ public function getNewAccessToken(): RenewedAccessToken */ public function getResponse(string $apiMethod, array $parameters = []): ResponseInterface { + $requestId = $this->requestIdGenerator->getRequestId(); $this->logger->info( 'getResponse.start', [ 'apiMethod' => $apiMethod, 'domainUrl' => $this->credentials->getDomainUrl(), 'parameters' => $parameters, + 'requestId' => $requestId ] ); @@ -150,9 +171,15 @@ public function getResponse(string $apiMethod, array $parameters = []): Response $parameters['auth'] = $this->getCredentials()->getAccessToken()->getAccessToken(); } + $requestOptions = [ 'json' => $parameters, - 'headers' => $this->getDefaultHeaders(), + 'headers' => array_merge( + $this->getDefaultHeaders(), + [ + $this->requestIdGenerator->getHeaderFieldName() => $requestId + ] + ), // disable redirects, try to catch portal change domain name event 'max_redirects' => 0, ]; @@ -163,6 +190,7 @@ public function getResponse(string $apiMethod, array $parameters = []): Response [ 'apiMethod' => $apiMethod, 'responseInfo' => $response->getInfo(), + 'requestId' => $requestId ] ); diff --git a/src/Core/CoreBuilder.php b/src/Core/CoreBuilder.php index 8e5b99d8..8f0d7960 100644 --- a/src/Core/CoreBuilder.php +++ b/src/Core/CoreBuilder.php @@ -9,6 +9,8 @@ use Bitrix24\SDK\Core\Credentials\Credentials; use Bitrix24\SDK\Core\Credentials\WebhookUrl; use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Infrastructure\HttpClient\RequestId\DefaultRequestIdGenerator; +use Bitrix24\SDK\Infrastructure\HttpClient\RequestId\RequestIdGeneratorInterface; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; use Symfony\Component\EventDispatcher\EventDispatcher; @@ -23,12 +25,13 @@ */ class CoreBuilder { - protected ?ApiClientInterface $apiClient; - protected HttpClientInterface $httpClient; - protected EventDispatcherInterface $eventDispatcher; - protected LoggerInterface $logger; - protected ?Credentials $credentials; - protected ApiLevelErrorHandler $apiLevelErrorHandler; + private ?ApiClientInterface $apiClient; + private HttpClientInterface $httpClient; + private EventDispatcherInterface $eventDispatcher; + private LoggerInterface $logger; + private ?Credentials $credentials; + private ApiLevelErrorHandler $apiLevelErrorHandler; + private RequestIdGeneratorInterface $requestIdGenerator; /** * CoreBuilder constructor. @@ -46,6 +49,12 @@ public function __construct() $this->credentials = null; $this->apiClient = null; $this->apiLevelErrorHandler = new ApiLevelErrorHandler($this->logger); + $this->requestIdGenerator = new DefaultRequestIdGenerator(); + } + + public function withRequestIdGenerator(RequestIdGeneratorInterface $requestIdGenerator): void + { + $this->requestIdGenerator = $requestIdGenerator; } /** @@ -101,6 +110,7 @@ public function build(): CoreInterface $this->apiClient = new ApiClient( $this->credentials, $this->httpClient, + $this->requestIdGenerator, $this->logger ); } diff --git a/src/Infrastructure/HttpClient/RequestId/DefaultRequestIdGenerator.php b/src/Infrastructure/HttpClient/RequestId/DefaultRequestIdGenerator.php new file mode 100644 index 00000000..05fba394 --- /dev/null +++ b/src/Infrastructure/HttpClient/RequestId/DefaultRequestIdGenerator.php @@ -0,0 +1,22 @@ +toRfc4122(); + } + + public function getHeaderFieldName(): string + { + return 'X-Request-ID'; + } +} \ No newline at end of file diff --git a/src/Infrastructure/HttpClient/RequestId/RequestIdGeneratorInterface.php b/src/Infrastructure/HttpClient/RequestId/RequestIdGeneratorInterface.php new file mode 100644 index 00000000..60dd9f0f --- /dev/null +++ b/src/Infrastructure/HttpClient/RequestId/RequestIdGeneratorInterface.php @@ -0,0 +1,12 @@ + Date: Sun, 26 Nov 2023 02:23:22 +0600 Subject: [PATCH 486/647] first version Signed-off-by: mesilov --- .../RequestId/DefaultRequestIdGenerator.php | 36 +++++++++++++-- .../DefaultRequestIdGeneratorTest.php | 44 +++++++++++++++++++ 2 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 tests/Unit/Infrastructure/HttpClient/RequestId/DefaultRequestIdGeneratorTest.php diff --git a/src/Infrastructure/HttpClient/RequestId/DefaultRequestIdGenerator.php b/src/Infrastructure/HttpClient/RequestId/DefaultRequestIdGenerator.php index 05fba394..d0332e8b 100644 --- a/src/Infrastructure/HttpClient/RequestId/DefaultRequestIdGenerator.php +++ b/src/Infrastructure/HttpClient/RequestId/DefaultRequestIdGenerator.php @@ -8,15 +8,43 @@ class DefaultRequestIdGenerator implements RequestIdGeneratorInterface { - public function getRequestId(): string + private const DEFAULT_REQUEST_ID_FIELD_NAME = 'X-Request-ID'; + private const KEY_NAME_VARIANTS = [ + 'REQUEST_ID', + 'HTTP_X_REQUEST_ID', + 'UNIQUE_ID' + ]; + + private function generate(): string { - // get from server fields - // if empty - generate return Uuid::v7()->toRfc4122(); } + private function findExists(): ?string + { + $candidate = null; + foreach(self::KEY_NAME_VARIANTS as $key) + { + if(!empty($_SERVER[$key])) + { + $candidate = $_SERVER[$key]; + break; + } + } + return $candidate; + } + + public function getRequestId(): string + { + $reqId = $this->findExists(); + if ($reqId === null) { + $reqId = $this->generate(); + } + return $reqId; + } + public function getHeaderFieldName(): string { - return 'X-Request-ID'; + return self::DEFAULT_REQUEST_ID_FIELD_NAME; } } \ No newline at end of file diff --git a/tests/Unit/Infrastructure/HttpClient/RequestId/DefaultRequestIdGeneratorTest.php b/tests/Unit/Infrastructure/HttpClient/RequestId/DefaultRequestIdGeneratorTest.php new file mode 100644 index 00000000..fab333b8 --- /dev/null +++ b/tests/Unit/Infrastructure/HttpClient/RequestId/DefaultRequestIdGeneratorTest.php @@ -0,0 +1,44 @@ +assertEquals($requestId, $gen->getRequestId()); + unset($_SERVER[$requestIdKey]); + } + + public function requestIdKeyDataProvider(): Generator + { + yield 'REQUEST_ID' => [ + 'REQUEST_ID', + Uuid::v7()->toRfc4122() + ]; + yield 'HTTP_X_REQUEST_ID' => [ + 'HTTP_X_REQUEST_ID', + Uuid::v7()->toRfc4122() + ]; + yield 'UNIQUE_ID' => [ + 'UNIQUE_ID', + Uuid::v7()->toRfc4122() + ]; + } +} From 2a50cabc6baaa53957b4a71aaee34d35cb674041 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 10 Dec 2023 02:14:58 +0600 Subject: [PATCH 487/647] Add Request ID to query string parameters The Request ID parameter is now included in query strings in addition to the header field for improved tracking. This change was made to accommodate for the current version of the Bitrix24 API that does not use Request ID from headers. A corresponding `getQueryStringParameterName` method was also added to the `RequestIdGeneratorInterface`. Signed-off-by: mesilov --- src/Core/ApiClient.php | 7 +++--- .../RequestId/DefaultRequestIdGenerator.php | 23 +++++++++++-------- .../RequestId/RequestIdGeneratorInterface.php | 2 ++ 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/Core/ApiClient.php b/src/Core/ApiClient.php index 9f2f6125..821c1172 100644 --- a/src/Core/ApiClient.php +++ b/src/Core/ApiClient.php @@ -84,7 +84,6 @@ public function getCredentials(): Credentials * @return RenewedAccessToken * @throws InvalidArgumentException * @throws TransportExceptionInterface - * @throws \JsonException * @throws TransportException */ public function getNewAccessToken(): RenewedAccessToken @@ -110,6 +109,7 @@ public function getNewAccessToken(): RenewedAccessToken 'client_id' => $this->getCredentials()->getApplicationProfile()->getClientId(), 'client_secret' => $this->getCredentials()->getApplicationProfile()->getClientSecret(), 'refresh_token' => $this->getCredentials()->getAccessToken()->getRefreshToken(), + $this->requestIdGenerator->getQueryStringParameterName() => $requestId ] ) ); @@ -170,8 +170,9 @@ public function getResponse(string $apiMethod, array $parameters = []): Response } $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; $requestOptions = [ 'json' => $parameters, 'headers' => array_merge( diff --git a/src/Infrastructure/HttpClient/RequestId/DefaultRequestIdGenerator.php b/src/Infrastructure/HttpClient/RequestId/DefaultRequestIdGenerator.php index d0332e8b..1fde5608 100644 --- a/src/Infrastructure/HttpClient/RequestId/DefaultRequestIdGenerator.php +++ b/src/Infrastructure/HttpClient/RequestId/DefaultRequestIdGenerator.php @@ -8,13 +8,20 @@ class DefaultRequestIdGenerator implements RequestIdGeneratorInterface { - private const DEFAULT_REQUEST_ID_FIELD_NAME = 'X-Request-ID'; + private const DEFAULT_REQUEST_ID_HEADER_FIELD_NAME = 'X-Request-ID'; + private const DEFAULT_QUERY_STRING_PARAMETER_NAME = 'request_id'; private const KEY_NAME_VARIANTS = [ 'REQUEST_ID', 'HTTP_X_REQUEST_ID', 'UNIQUE_ID' ]; + public function getQueryStringParameterName(): string + { + return self::DEFAULT_QUERY_STRING_PARAMETER_NAME; + } + + private function generate(): string { return Uuid::v7()->toRfc4122(); @@ -23,13 +30,11 @@ private function generate(): string private function findExists(): ?string { $candidate = null; - foreach(self::KEY_NAME_VARIANTS as $key) - { - if(!empty($_SERVER[$key])) - { - $candidate = $_SERVER[$key]; - break; - } + foreach (self::KEY_NAME_VARIANTS as $key) { + if (!empty($_SERVER[$key])) { + $candidate = $_SERVER[$key]; + break; + } } return $candidate; } @@ -45,6 +50,6 @@ public function getRequestId(): string public function getHeaderFieldName(): string { - return self::DEFAULT_REQUEST_ID_FIELD_NAME; + return self::DEFAULT_REQUEST_ID_HEADER_FIELD_NAME; } } \ No newline at end of file diff --git a/src/Infrastructure/HttpClient/RequestId/RequestIdGeneratorInterface.php b/src/Infrastructure/HttpClient/RequestId/RequestIdGeneratorInterface.php index 60dd9f0f..77ba06b2 100644 --- a/src/Infrastructure/HttpClient/RequestId/RequestIdGeneratorInterface.php +++ b/src/Infrastructure/HttpClient/RequestId/RequestIdGeneratorInterface.php @@ -9,4 +9,6 @@ interface RequestIdGeneratorInterface public function getRequestId(): string; public function getHeaderFieldName(): string; + + public function getQueryStringParameterName():string; } \ No newline at end of file From ea0bed3996113232239befd7fa25975ce180dcd7 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 4 Jan 2024 00:21:32 +0600 Subject: [PATCH 488/647] add windows platforms in unit-tests Signed-off-by: mesilov --- .github/workflows/phpunit.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index e1512640..713330af 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -11,14 +11,15 @@ jobs: tests: name: "PHPUnit tests" - runs-on: ubuntu-latest + runs-on: ${{ matrix.operating-system }} + strategy: matrix: php-version: - - "8.1" - - "8.2" + - "8.3" dependencies: [ highest ] + operating-system: [ ubuntu-latest, windows-latest ] steps: - name: "Checkout" From e220737930c0933c7e3a84427977b434575a673f Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 4 Jan 2024 00:24:17 +0600 Subject: [PATCH 489/647] bump php version requirements Signed-off-by: mesilov --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index e2dc8095..084b2a9d 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ } ], "require": { - "php": "8.1.* || 8.2.*", + "php": "8.1.* || 8.2.* || 8.3.*", "ext-json": "*", "ext-bcmath": "*", "ext-curl": "*", From e52866c54866bea88677598002cc1980c98d740e Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 4 Jan 2024 00:34:57 +0600 Subject: [PATCH 490/647] add extensions Signed-off-by: mesilov --- .github/workflows/phpunit.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 713330af..f64d078b 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -30,6 +30,7 @@ jobs: with: coverage: "none" php-version: "${{ matrix.php-version }}" + extensions: json, bcmath, curl - name: "Install dependencies" run: | From 2fb317b1a813691aa58ab830ce38bf1ece000ade Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 4 Jan 2024 00:37:46 +0600 Subject: [PATCH 491/647] add extension intl Signed-off-by: mesilov --- .github/workflows/phpunit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index f64d078b..83c2d3c1 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -30,7 +30,7 @@ jobs: with: coverage: "none" php-version: "${{ matrix.php-version }}" - extensions: json, bcmath, curl + extensions: json, bcmath, curl, intl - name: "Install dependencies" run: | From 1a4278e98b4773e631ce92be8bdff47811aac7a0 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 4 Jan 2024 00:42:35 +0600 Subject: [PATCH 492/647] fix workflows Signed-off-by: mesilov --- .github/workflows/phpstan.yml | 5 ++--- .github/workflows/phpunit.yml | 5 +++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index 068e9864..70847366 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -13,8 +13,7 @@ jobs: fail-fast: false matrix: php-version: - - "8.1" - - "8.2" + - "8.3" dependencies: [ highest ] steps: @@ -26,7 +25,7 @@ jobs: with: coverage: "none" php-version: "${{ matrix.php-version }}" - extensions: mbstring + extensions: json, bcmath, curl, intl, mbstring tools: composer:v2 - name: "Install lowest dependencies" diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 83c2d3c1..f1244128 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -13,10 +13,11 @@ jobs: runs-on: ${{ matrix.operating-system }} - strategy: matrix: php-version: + - "8.1" + - "8.2" - "8.3" dependencies: [ highest ] operating-system: [ ubuntu-latest, windows-latest ] @@ -30,7 +31,7 @@ jobs: with: coverage: "none" php-version: "${{ matrix.php-version }}" - extensions: json, bcmath, curl, intl + extensions: json, bcmath, curl, intl, mbstring - name: "Install dependencies" run: | From 6a6ccef21406dba8778d730eb2d0e31cc06078d5 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 4 Jan 2024 10:22:15 +0600 Subject: [PATCH 493/647] bump php version to 8.3.* Signed-off-by: mesilov --- .github/workflows/phpunit.yml | 2 - composer.json | 43 +++++++++++----------- phpunit.xml.dist | 40 +++++++++----------- src/Services/CRM/Contact/Service/Batch.php | 29 ++------------- 4 files changed, 41 insertions(+), 73 deletions(-) diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index f1244128..14797cdc 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -16,8 +16,6 @@ jobs: strategy: matrix: php-version: - - "8.1" - - "8.2" - "8.3" dependencies: [ highest ] operating-system: [ ubuntu-latest, windows-latest ] diff --git a/composer.json b/composer.json index 084b2a9d..67e5a23e 100644 --- a/composer.json +++ b/composer.json @@ -12,38 +12,37 @@ "license": "MIT", "authors": [ { - "name": "Maxim Mesilov", + "name": "Maksim Mesilov", "homepage": "https://github.com/mesilov/" - }, - { - "name": "Kirill Hramov", - "homepage": "https://github.com/KarlsonComplete" } ], + "config": { + "sort-packages": true + }, "require": { - "php": "8.1.* || 8.2.* || 8.3.*", + "php": "8.3.*", "ext-json": "*", "ext-bcmath": "*", "ext-curl": "*", - "psr/log": "^1.1.4 || ^2.0 || ^3.0", + "ext-intl": "*", + "psr/log": "1.1.*", "fig/http-message-util": "1.1.*", - "symfony/http-client": "5.4.* || 6.*", - "symfony/http-client-contracts": "^2.5 || ^3.1", - "symfony/http-foundation": "5.4.* || 6.*", - "symfony/event-dispatcher": "5.4.* || 6.*", - "ramsey/uuid": "^4.2.3", - "moneyphp/money": "3.* || 4.*", - "symfony/uid": "6.*", - "ext-intl": "*" + "ramsey/uuid": "4.7.*", + "moneyphp/money": "4.3.*", + "symfony/http-client": "7.0.*", + "symfony/http-client-contracts": "3.4.*", + "symfony/http-foundation": "7.0.*", + "symfony/event-dispatcher": "7.0.*", + "symfony/uid": "7.0.*" }, "require-dev": { - "monolog/monolog": "2.1.*", - "symfony/console": "5.4.* || 6.*", - "symfony/dotenv": "5.4.* || 6.*", - "symfony/debug-bundle": "5.4.* || 6.*", - "phpstan/phpstan": "1.*", - "phpunit/phpunit": "9.5.*", - "symfony/stopwatch": "5.4.* || 6.*", + "monolog/monolog": "2.9.*", + "phpstan/phpstan": "1.10.*", + "phpunit/phpunit": "10.5.*", + "symfony/console": "7.0.*", + "symfony/dotenv": "7.0.*", + "symfony/debug-bundle": "7.0.*", + "symfony/stopwatch": "7.0.*", "roave/security-advisories": "dev-master" }, "autoload": { diff --git a/phpunit.xml.dist b/phpunit.xml.dist index a3e33d9d..eb16a1a7 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,25 +1,19 @@ - - - - ./src - - - - - - - - ./tests/Unit - - - ./tests/Integration - - + + + + + + + ./tests/Unit + + + ./tests/Integration + + + + + ./src + + diff --git a/src/Services/CRM/Contact/Service/Batch.php b/src/Services/CRM/Contact/Service/Batch.php index f2981421..0d929947 100644 --- a/src/Services/CRM/Contact/Service/Batch.php +++ b/src/Services/CRM/Contact/Service/Batch.php @@ -121,8 +121,8 @@ class Batch extends AbstractBatchService * WEB?: string, * IM?: string, * } $filter - * @param array $select = ['ID','HONORIFIC','NAME','SECOND_NAME','LAST_NAME','PHOTO','BIRTHDATE','TYPE_ID','SOURCE_ID','SOURCE_DESCRIPTION','POST','ADDRESS','ADDRESS_2','ADDRESS_CITY','ADDRESS_POSTAL_CODE','ADDRESS_REGION','ADDRESS_PROVINCE','ADDRESS_COUNTRY','ADDRESS_COUNTRY_CODE','ADDRESS_LOC_ADDR_ID','COMMENTS','OPENED','EXPORT','HAS_PHONE','HAS_EMAIL','HAS_IMOL','ASSIGNED_BY_ID','CREATED_BY_ID','MODIFY_BY_ID','DATE_CREATE','DATE_MODIFY','COMPANY_ID','COMPANY_IDS','LEAD_ID','ORIGINATOR_ID','ORIGIN_ID','ORIGIN_VERSION','FACE_ID','UTM_SOURCE','UTM_MEDIUM','UTM_CAMPAIGN','UTM_CONTENT','UTM_TERM','PHONE','EMAIL','WEB','IM'] - * @param int|null $limit + * @param array $select = ['ID','HONORIFIC','NAME','SECOND_NAME','LAST_NAME','PHOTO','BIRTHDATE','TYPE_ID','SOURCE_ID','SOURCE_DESCRIPTION','POST','ADDRESS','ADDRESS_2','ADDRESS_CITY','ADDRESS_POSTAL_CODE','ADDRESS_REGION','ADDRESS_PROVINCE','ADDRESS_COUNTRY','ADDRESS_COUNTRY_CODE','ADDRESS_LOC_ADDR_ID','COMMENTS','OPENED','EXPORT','HAS_PHONE','HAS_EMAIL','HAS_IMOL','ASSIGNED_BY_ID','CREATED_BY_ID','MODIFY_BY_ID','DATE_CREATE','DATE_MODIFY','COMPANY_ID','COMPANY_IDS','LEAD_ID','ORIGINATOR_ID','ORIGIN_ID','ORIGIN_VERSION','FACE_ID','UTM_SOURCE','UTM_MEDIUM','UTM_CAMPAIGN','UTM_CONTENT','UTM_TERM','PHONE','EMAIL','WEB','IM'] + * @param int|null $limit * * @return Generator * @throws BaseException @@ -220,9 +220,7 @@ public function add(array $contacts): Generator * 'params' => [] * ] * - * @param array $entityItems - * - * @param array $entityItems + * @param array $entityItems * @return Generator * @throws BaseException */ @@ -247,25 +245,4 @@ public function delete(array $contactId): Generator yield $key => new DeletedItemBatchResult($item); } } - - /** - * Update contact - * - * Update elements in array with structure - * element_id => [ // contact id - * 'fields' => [], // contact fields to update - * 'params' => [] - * ] - * - * @param array $entityItems - * - * @return \Generator - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - */ - public function update(array $entityItems): Generator - { - foreach ($this->batch->updateEntityItems('crm.contact.update', $entityItems) as $key => $item) { - yield $key => new UpdatedItemBatchResult($item); - } - } } \ No newline at end of file From 5d658288b721843795d1de3b7bd74099d4e475eb Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 4 Jan 2024 17:44:25 +0600 Subject: [PATCH 494/647] add multifields Signed-off-by: mesilov --- CHANGELOG.md | 7 +- composer.json | 3 +- .../CRM/Common/Result/AbstractCrmItem.php | 43 +++++++- .../Result/SystemFields/Types/Email.php | 25 +++++ .../SystemFields/Types/EmailValueType.php | 13 +++ .../SystemFields/Types/InstantMessenger.php | 25 +++++ .../Types/InstantMessengerValueType.php | 22 ++++ .../Result/SystemFields/Types/Website.php | 25 +++++ .../SystemFields/Types/WebsiteValueType.php | 16 +++ .../CRM/Contact/Result/ContactItemResult.php | 9 +- .../CRM/Lead/Result/LeadItemResult.php | 12 ++- .../CRM/Contact/Service/ContactTest.php | 100 ++++++++++++++++++ 12 files changed, 286 insertions(+), 14 deletions(-) create mode 100644 src/Services/CRM/Common/Result/SystemFields/Types/Email.php create mode 100644 src/Services/CRM/Common/Result/SystemFields/Types/EmailValueType.php create mode 100644 src/Services/CRM/Common/Result/SystemFields/Types/InstantMessenger.php create mode 100644 src/Services/CRM/Common/Result/SystemFields/Types/InstantMessengerValueType.php create mode 100644 src/Services/CRM/Common/Result/SystemFields/Types/Website.php create mode 100644 src/Services/CRM/Common/Result/SystemFields/Types/WebsiteValueType.php diff --git a/CHANGELOG.md b/CHANGELOG.md index b945cb24..f4a5cdaf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,13 +4,13 @@ ### Added +* ❗️add php 8.3 support * add `Symfony\Component\Uid\Uuid` requirements * add contracts for bitrix24 applications based on bitrix24-php-sdk - `Bitrix24\SDK\Application\Contracts`, now added `Bitrix24Account` * add [service builder factory](https://github.com/mesilov/bitrix24-php-sdk/issues/328) * add method `Bitrix24\SDK\Core\Credentials\Scope::initFromString` * add method `Bitrix24\SDK\Application\ApplicationStatus::initFromString` -* ❗️add php 8.2 support * add system CRM multi-field type `Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\Phone` * add scope `user`,`user_basic`,`user_brief`,`user.userfield` and services [add scope user support](https://github.com/mesilov/bitrix24-php-sdk/issues/339) @@ -25,6 +25,11 @@ * add enum `DealStageSemanticId` * add Duplicate search support for `Bitrix24\SDK\Services\CRM\Duplicates\Service\Duplicate` * add `x-request-id` [header support](https://github.com/mesilov/bitrix24-php-sdk/issues/354) +* add CRM multifields support [header support](https://github.com/mesilov/bitrix24-php-sdk/issues/338) + * `Email` + * `Phone` + * `Website` + * `IM` ### Changed diff --git a/composer.json b/composer.json index 67e5a23e..c6cf5d7c 100644 --- a/composer.json +++ b/composer.json @@ -43,7 +43,8 @@ "symfony/dotenv": "7.0.*", "symfony/debug-bundle": "7.0.*", "symfony/stopwatch": "7.0.*", - "roave/security-advisories": "dev-master" + "roave/security-advisories": "dev-master", + "fakerphp/faker": "1.23.*" }, "autoload": { "psr-4": { diff --git a/src/Services/CRM/Common/Result/AbstractCrmItem.php b/src/Services/CRM/Common/Result/AbstractCrmItem.php index 307fc025..f7d9c321 100644 --- a/src/Services/CRM/Common/Result/AbstractCrmItem.php +++ b/src/Services/CRM/Common/Result/AbstractCrmItem.php @@ -5,8 +5,11 @@ namespace Bitrix24\SDK\Services\CRM\Common\Result; use Bitrix24\SDK\Core\Result\AbstractItem; +use Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\Email; +use Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\InstantMessenger; use Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\Phone; use Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\PhoneValueType; +use Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\Website; use Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNotFoundException; use DateTimeImmutable; use Money\Currency; @@ -14,7 +17,7 @@ class AbstractCrmItem extends AbstractItem { - private const CRM_USERFIELD_PREFIX = 'UF_CRM_'; + private const string CRM_USERFIELD_PREFIX = 'UF_CRM_'; /** * @var Currency @@ -32,7 +35,7 @@ public function __construct(array $data, Currency $currency = null) /** * @param int|string $offset * - * @return bool|\DateTimeImmutable|int|mixed|null + * @return bool|DateTimeImmutable|int|mixed|null */ public function __get($offset) @@ -132,8 +135,38 @@ public function __get($offset) } $items = []; - foreach ($this->data[$offset] as $phone) { - $items[] = new Phone($phone); + foreach ($this->data[$offset] as $item) { + $items[] = new Phone($item); + } + return $items; + case 'EMAIL': + if (!$this->isKeyExists($offset)) { + return []; + } + + $items = []; + foreach ($this->data[$offset] as $item) { + $items[] = new Email($item); + } + return $items; + case 'WEB': + if (!$this->isKeyExists($offset)) { + return []; + } + + $items = []; + foreach ($this->data[$offset] as $item) { + $items[] = new Website($item); + } + return $items; + case 'IM': + if (!$this->isKeyExists($offset)) { + return []; + } + + $items = []; + foreach ($this->data[$offset] as $item) { + $items[] = new InstantMessenger($item); } return $items; case 'currencyId': @@ -154,7 +187,7 @@ public function __get($offset) */ protected function getKeyWithUserfieldByFieldName(string $fieldName) { - if(!str_starts_with($fieldName, self::CRM_USERFIELD_PREFIX)) { + if (!str_starts_with($fieldName, self::CRM_USERFIELD_PREFIX)) { $fieldName = self::CRM_USERFIELD_PREFIX . $fieldName; } if (!$this->isKeyExists($fieldName)) { diff --git a/src/Services/CRM/Common/Result/SystemFields/Types/Email.php b/src/Services/CRM/Common/Result/SystemFields/Types/Email.php new file mode 100644 index 00000000..603cdae9 --- /dev/null +++ b/src/Services/CRM/Common/Result/SystemFields/Types/Email.php @@ -0,0 +1,25 @@ + $this->data[$offset], + 'ID' => (int)$this->data['ID'], + 'VALUE_TYPE' => EmailValueType::from($this->data['VALUE_TYPE']), + default => parent::__get($offset), + }; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Common/Result/SystemFields/Types/EmailValueType.php b/src/Services/CRM/Common/Result/SystemFields/Types/EmailValueType.php new file mode 100644 index 00000000..5f3bc5b2 --- /dev/null +++ b/src/Services/CRM/Common/Result/SystemFields/Types/EmailValueType.php @@ -0,0 +1,13 @@ + $this->data[$offset], + 'ID' => (int)$this->data['ID'], + 'VALUE_TYPE' => EmailValueType::from($this->data['VALUE_TYPE']), + default => parent::__get($offset), + }; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Common/Result/SystemFields/Types/InstantMessengerValueType.php b/src/Services/CRM/Common/Result/SystemFields/Types/InstantMessengerValueType.php new file mode 100644 index 00000000..87b5c223 --- /dev/null +++ b/src/Services/CRM/Common/Result/SystemFields/Types/InstantMessengerValueType.php @@ -0,0 +1,22 @@ + $this->data[$offset], + 'ID' => (int)$this->data['ID'], + 'VALUE_TYPE' => EmailValueType::from($this->data['VALUE_TYPE']), + default => parent::__get($offset), + }; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Common/Result/SystemFields/Types/WebsiteValueType.php b/src/Services/CRM/Common/Result/SystemFields/Types/WebsiteValueType.php new file mode 100644 index 00000000..dd9f322d --- /dev/null +++ b/src/Services/CRM/Common/Result/SystemFields/Types/WebsiteValueType.php @@ -0,0 +1,16 @@ +assertEquals($totalBefore + $newContactsCount, $totalAfter); } + /** + * @return void + * @covers Contact::get + * @covers Contact::add + * @throws Core\Exceptions\TransportException + * @throws Core\Exceptions\BaseException + */ + public function testGetEmail(): void + { + $email = $this->faker->email(); + $this->assertEquals($email, + $this->contactService->get( + $this->contactService->add([ + 'NAME' => $this->faker->name(), + 'EMAIL' => [ + [ + 'VALUE' => $email, + 'VALUE_TYPE' => EmailValueType::work->name, + ] + ], + ])->getId())->contact()->EMAIL[0]->VALUE); + } + + /** + * @return void + * @covers Contact::get + * @covers Contact::add + * @throws Core\Exceptions\TransportException + * @throws Core\Exceptions\BaseException + */ + public function testGetPhone(): void + { + $phone = $this->faker->e164PhoneNumber(); + $this->assertEquals($phone, + $this->contactService->get( + $this->contactService->add([ + 'NAME' => $this->faker->name(), + 'PHONE' => [ + [ + 'VALUE' => $phone, + 'VALUE_TYPE' => PhoneValueType::work->name, + ] + ], + ])->getId())->contact()->PHONE[0]->VALUE); + } + + /** + * @return void + * @covers Contact::get + * @covers Contact::add + * @throws Core\Exceptions\TransportException + * @throws Core\Exceptions\BaseException + */ + public function testGetInstantMessenger(): void + { + $phone = $this->faker->e164PhoneNumber(); + $this->assertEquals($phone, + $this->contactService->get( + $this->contactService->add([ + 'NAME' => $this->faker->name(), + 'IM' => [ + [ + 'VALUE' => $phone, + 'VALUE_TYPE' => InstantMessengerValueType::telegram->name, + ] + ], + ])->getId())->contact()->IM[0]->VALUE); + } + + /** + * @return void + * @covers Contact::get + * @covers Contact::add + * @throws Core\Exceptions\TransportException + * @throws Core\Exceptions\BaseException + */ + public function testGetWebsite(): void + { + $url = $this->faker->url(); + $this->assertEquals($url, + $this->contactService->get( + $this->contactService->add([ + 'NAME' => $this->faker->name(), + 'WEB' => [ + [ + 'VALUE' => $url, + 'VALUE_TYPE' => WebsiteValueType::work, + ] + ], + ])->getId())->contact()->WEB[0]->VALUE); + } + public function setUp(): void { $this->contactService = Fabric::getServiceBuilder()->getCRMScope()->contact(); + $this->faker = Faker\Factory::create(); } } \ No newline at end of file From 644a0ad429ab59217140a25d61201c710edcd339 Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 12 Jan 2024 23:47:35 +0600 Subject: [PATCH 495/647] change query string parameter name Signed-off-by: mesilov --- .../HttpClient/RequestId/DefaultRequestIdGenerator.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Infrastructure/HttpClient/RequestId/DefaultRequestIdGenerator.php b/src/Infrastructure/HttpClient/RequestId/DefaultRequestIdGenerator.php index 1fde5608..9b49016d 100644 --- a/src/Infrastructure/HttpClient/RequestId/DefaultRequestIdGenerator.php +++ b/src/Infrastructure/HttpClient/RequestId/DefaultRequestIdGenerator.php @@ -8,9 +8,9 @@ class DefaultRequestIdGenerator implements RequestIdGeneratorInterface { - private const DEFAULT_REQUEST_ID_HEADER_FIELD_NAME = 'X-Request-ID'; - private const DEFAULT_QUERY_STRING_PARAMETER_NAME = 'request_id'; - private const KEY_NAME_VARIANTS = [ + private const string DEFAULT_REQUEST_ID_HEADER_FIELD_NAME = 'X-Request-ID'; + private const string DEFAULT_QUERY_STRING_PARAMETER_NAME = 'bx24_request_id'; + private const array KEY_NAME_VARIANTS = [ 'REQUEST_ID', 'HTTP_X_REQUEST_ID', 'UNIQUE_ID' From 3b1abfac4ff7790feda12f60b26b922373d6f263 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 5 Feb 2024 00:34:18 +0600 Subject: [PATCH 496/647] Implement catalog scope services New classes related to Catalog scope services have been created and integrated into the existing structure. This includes product-related result classes `ProductResult`, `ProductsResult`, `ProductItemResult` and service classes `Product` and `Batch`. Additionally, a `CatalogServiceBuilder` is added to construct the catalog service, and a `ProductType` enumeration has been defined to set product types. The commit also includes an update in the `CHANGELOG.md`. Signed-off-by: mesilov --- CHANGELOG.md | 1 + .../Catalog/CatalogServiceBuilder.php | 23 ++++ src/Services/Catalog/Common/ProductType.php | 14 +++ .../Common/Result/AbstractCatalogItem.php | 105 ++++++++++++++++++ .../Product/Result/ProductItemResult.php | 57 ++++++++++ .../Catalog/Product/Result/ProductResult.php | 15 +++ .../Catalog/Product/Result/ProductsResult.php | 25 +++++ .../Catalog/Product/Service/Batch.php | 22 ++++ .../Catalog/Product/Service/Product.php | 83 ++++++++++++++ src/Services/ServiceBuilder.php | 15 ++- 10 files changed, 355 insertions(+), 5 deletions(-) create mode 100644 src/Services/Catalog/CatalogServiceBuilder.php create mode 100644 src/Services/Catalog/Common/ProductType.php create mode 100644 src/Services/Catalog/Common/Result/AbstractCatalogItem.php create mode 100644 src/Services/Catalog/Product/Result/ProductItemResult.php create mode 100644 src/Services/Catalog/Product/Result/ProductResult.php create mode 100644 src/Services/Catalog/Product/Result/ProductsResult.php create mode 100644 src/Services/Catalog/Product/Service/Batch.php create mode 100644 src/Services/Catalog/Product/Service/Product.php diff --git a/CHANGELOG.md b/CHANGELOG.md index f4a5cdaf..edac8b24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ * `Phone` * `Website` * `IM` +* add [Catalog](https://github.com/mesilov/bitrix24-php-sdk/issues/364) scope services support ### Changed diff --git a/src/Services/Catalog/CatalogServiceBuilder.php b/src/Services/Catalog/CatalogServiceBuilder.php new file mode 100644 index 00000000..108db59d --- /dev/null +++ b/src/Services/Catalog/CatalogServiceBuilder.php @@ -0,0 +1,23 @@ +serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Catalog\Product\Service\Product( + new Catalog\Product\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } +} \ No newline at end of file diff --git a/src/Services/Catalog/Common/ProductType.php b/src/Services/Catalog/Common/ProductType.php new file mode 100644 index 00000000..0972c1a2 --- /dev/null +++ b/src/Services/Catalog/Common/ProductType.php @@ -0,0 +1,14 @@ +currency = $currency; + } + } + + /** + * @param int|string $offset + * + * @return bool|DateTimeImmutable|int|mixed|null + */ + + public function __get($offset) + { + switch ($offset) { + case 'active': + case 'available': + case 'bundle': + return $this->data[$offset] === 'Y'; + case 'barcodeMulti': + case 'canBuyZero': + if ($this->data[$offset] !== null) { + return $this->data[$offset] === 'Y'; + } + return null; + case 'code': + case 'detailText': + case 'detailTextType': + case 'name': + case 'previewText': + case 'previewTextType': + case 'xmlId': + return (string)$this->data[$offset]; + case 'createdBy': + case 'iblockId': + case 'iblockSectionId': + case 'id': + case 'modifiedBy': + case 'sort': + case 'height': + case 'length': + if ($this->data[$offset] !== '' && $this->data[$offset] !== null) { + return (int)$this->data[$offset]; + } + break; + case 'dateActiveFrom': + case 'dateActiveTo': + case 'dateCreate': + case 'timestampX': + if ($this->data[$offset] !== '') { + return DateTimeImmutable::createFromFormat(DATE_ATOM, $this->data[$offset]); + } + + return null; + case 'type': + return ProductType::from($this->data[$offset]); + } + + return $this->data[$offset] ?? null; + } + + /** + * get userfield by field name + * + * @param string $fieldName + * + * @return mixed|null + * @throws UserfieldNotFoundException + */ + protected function getKeyWithUserfieldByFieldName(string $fieldName) + { + if (!str_starts_with($fieldName, self::CRM_USERFIELD_PREFIX)) { + $fieldName = self::CRM_USERFIELD_PREFIX . $fieldName; + } + if (!$this->isKeyExists($fieldName)) { + throw new UserfieldNotFoundException(sprintf('crm userfield not found by field name %s', $fieldName)); + } + + return $this->$fieldName; + } +} \ No newline at end of file diff --git a/src/Services/Catalog/Product/Result/ProductItemResult.php b/src/Services/Catalog/Product/Result/ProductItemResult.php new file mode 100644 index 00000000..475c4bff --- /dev/null +++ b/src/Services/Catalog/Product/Result/ProductItemResult.php @@ -0,0 +1,57 @@ +getKeyWithUserfieldByFieldName($userfieldName); + } +} \ No newline at end of file diff --git a/src/Services/Catalog/Product/Result/ProductResult.php b/src/Services/Catalog/Product/Result/ProductResult.php new file mode 100644 index 00000000..3e5564fe --- /dev/null +++ b/src/Services/Catalog/Product/Result/ProductResult.php @@ -0,0 +1,15 @@ +getCoreResponse()->getResponseData()->getResult()['product']); + } +} \ No newline at end of file diff --git a/src/Services/Catalog/Product/Result/ProductsResult.php b/src/Services/Catalog/Product/Result/ProductsResult.php new file mode 100644 index 00000000..9f80be4e --- /dev/null +++ b/src/Services/Catalog/Product/Result/ProductsResult.php @@ -0,0 +1,25 @@ +getCoreResponse()->getResponseData()->getResult()['products'] as $product) { + $res[] = new ProductItemResult($product); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/Catalog/Product/Service/Batch.php b/src/Services/Catalog/Product/Service/Batch.php new file mode 100644 index 00000000..1bd42ef6 --- /dev/null +++ b/src/Services/Catalog/Product/Service/Batch.php @@ -0,0 +1,22 @@ +core->call('catalog.product.get', ['id' => $productId])); + } + + /** + * The method gets list of commercial catalog products by filter. + * + * @see https://training.bitrix24.com/rest_help/catalog/product/catalog_product_list.php + * @throws TransportException + * @throws BaseException + */ + public function list(array $select, array $filter, array $order, int $start): ProductsResult + { + return new ProductsResult($this->core->call('catalog.product.list', [ + 'select' => $select, + 'filter' => $filter, + 'order' => $order, + 'start' => $start + ])); + } + + /** + * The method returns commercial catalog product fields by filter. + * @see https://training.bitrix24.com/rest_help/catalog/product/catalog_product_getfieldsbyfilter.php + * + * @param int $iblockId + * @param ProductType $productType + * @param array|null $additionalFilter + * @return FieldsResult + * @throws BaseException + * @throws TransportException + */ + public function fieldsByFilter(int $iblockId, ProductType $productType, ?array $additionalFilter = null): FieldsResult + { + $filter = [ + 'iblockId' => $iblockId, + 'productType' => $productType->value + ]; + if ($additionalFilter !== null) { + $filter = array_merge($filter, $additionalFilter); + } + + return new FieldsResult($this->core->call('catalog.product.getFieldsByFilter', ['filter' => $filter])); + } +} \ No newline at end of file diff --git a/src/Services/ServiceBuilder.php b/src/Services/ServiceBuilder.php index e603ce1f..2f7b1ca3 100644 --- a/src/Services/ServiceBuilder.php +++ b/src/Services/ServiceBuilder.php @@ -4,6 +4,7 @@ namespace Bitrix24\SDK\Services; +use Bitrix24\SDK\Services\Catalog\CatalogServiceBuilder; use Bitrix24\SDK\Services\CRM\CRMServiceBuilder; use Bitrix24\SDK\Services\IM\IMServiceBuilder; use Bitrix24\SDK\Services\IMOpenLines\IMOpenLinesServiceBuilder; @@ -13,11 +14,6 @@ use Bitrix24\SDK\Services\UserConsent\UserConsentServiceBuilder; use Bitrix24\SDK\Services\Placement\PlacementServiceBuilder; -/** - * Class ServiceBuilder - * - * @package Bitrix24\SDK\Services - */ class ServiceBuilder extends AbstractServiceBuilder { /** @@ -104,6 +100,15 @@ public function getPlacementScope(): PlacementServiceBuilder return $this->serviceCache[__METHOD__]; } + public function getCatalogScope(): CatalogServiceBuilder + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new CatalogServiceBuilder($this->core, $this->batch, $this->bulkItemsReader, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + /** * @return TelephonyServiceBuilder */ From fe5a91ce4ed1b4ad417a41c07b283ed8584f7396 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 17 Feb 2024 18:54:43 +0600 Subject: [PATCH 497/647] Update GitHub workflows for multi-OS testing Updated workflow configurations to support both Ubuntu and Windows OS. The changes cover PHPUnit tests, PHPStan, Vendor integration, and Integration tests by adding matrix-operating-system variables. These modifications also include updates in the supported PHP versions, and disabling the "fail-fast" strategy to ensure tests across all OS complete before reporting. Signed-off-by: mesilov --- .github/workflows/integration.yml | 10 +++++----- .github/workflows/phpstan.yml | 4 +++- .github/workflows/phpunit.yml | 6 ++++-- .github/workflows/vendor-check.yml | 6 +++--- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index bb8210c7..2a6b4634 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -9,19 +9,19 @@ on: env: COMPOSER_FLAGS: "--ansi --no-interaction --no-progress --prefer-dist" BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK: ${{ secrets.BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK }} - TEST2_ENV: 12345 jobs: tests: name: "Integration tests" - - runs-on: ubuntu-latest - + runs-on: ${{ matrix.operating-system }} strategy: + fail-fast: false matrix: php-version: - - "8.1" + - "8.2" + - "8.3" dependencies: [ highest ] + operating-system: [ ubuntu-latest, windows-latest ] steps: diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index 70847366..64ea73b4 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -7,14 +7,16 @@ name: PHPStan checks jobs: static-analysis: name: "PHPStan" - runs-on: "ubuntu-latest" + 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" diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 14797cdc..00dc1d47 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -1,8 +1,8 @@ name: "PHPUnit tests" on: - - push - - pull_request + push: + pull_request: env: COMPOSER_FLAGS: "--ansi --no-interaction --no-progress --prefer-dist" @@ -14,8 +14,10 @@ jobs: runs-on: ${{ matrix.operating-system }} strategy: + fail-fast: false matrix: php-version: + - "8.2" - "8.3" dependencies: [ highest ] operating-system: [ ubuntu-latest, windows-latest ] diff --git a/.github/workflows/vendor-check.yml b/.github/workflows/vendor-check.yml index beaa80f5..74662014 100644 --- a/.github/workflows/vendor-check.yml +++ b/.github/workflows/vendor-check.yml @@ -8,20 +8,20 @@ on: env: COMPOSER_FLAGS: "--ansi --no-interaction --no-progress --prefer-dist" BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK: ${{ secrets.BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK }} - TEST2_ENV: 12345 jobs: tests: name: "Vendor integration tests" - runs-on: ubuntu-latest + runs-on: ${{ matrix.operating-system }} strategy: matrix: php-version: - - "8.1" - "8.2" + - "8.3" dependencies: [ highest ] + operating-system: [ ubuntu-latest, windows-latest ] steps: From 9c977bceb4497693d46ab24e2eac98a19de72af5 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 17 Feb 2024 19:14:11 +0600 Subject: [PATCH 498/647] Update PHP requirements and refactor README This commit updates the PHP version requirement in composer.json to allow either 8.2.* or 8.3.*, reflecting its compatibility with both. Moreover, the README file has been significantly refactored, removing unnecessary content, correcting a typo, and reorganizing the architecture section. Signed-off-by: mesilov --- CHANGELOG.md | 2 +- README.md | 248 ++++---------------------------------------------- composer.json | 2 +- 3 files changed, 20 insertions(+), 232 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index edac8b24..e31e28c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ### Added -* ❗️add php 8.3 support +* ❗️add php 8.3 support, drop 8.1 and 8.0 support * add `Symfony\Component\Uid\Uuid` requirements * add contracts for bitrix24 applications based on bitrix24-php-sdk - `Bitrix24\SDK\Application\Contracts`, now added `Bitrix24Account` diff --git a/README.md b/README.md index 97104ce4..27a56e2c 100644 --- a/README.md +++ b/README.md @@ -15,12 +15,6 @@ A powerful PHP library for the Bitrix24 REST API Integration tests run in GitHub actions with real Bitrix24 portal - -### BITRIX24-PHP-SDK Documentation - -- [Russian](/docs/RU/documentation.md) -- [English](/docs/EN/documentation.md) - ### BITRIX24-PHP-SDK ✨FEATURES✨ Support both auth modes: @@ -65,7 +59,7 @@ Performance improvements 🚀 - Performance first: - minimal impact on client code - ability to work with large amounts of data with constant memory consumption - - efficient operation of the API using butch requests + - efficient operation of the API using batch requests - Modern technology stack - based on [Symfony HttpClient](https://symfony.com/doc/current/http_client.html) - actual PHP versions language features @@ -77,48 +71,12 @@ Performance improvements 🚀 Help bitrix24-php-sdk by [boosty.to/bitrix24-php-sdk](https://boosty.to/bitrix24-php-sdk) its development! -### Architecture - -### Abstraction layers - -``` -- http protocol -- json data -- symfony http client -- \Bitrix24\SDK\Core\ApiClient - work with b24 rest-api endpoints - input: arrays \ strings - output: Symfony\Contracts\HttpClient\ResponseInterface, operate with strings - process: network operations -- \Bitrix24\SDK\Services\Main - work with b24 rest-api entities - input: arrays \ strings (?) or queries? - output: b24 response dto - process: b24 entities, operate with -``` - -### File Structure - -``` - /Core - ApiClient.php - default api-client, work on http abstraction layer, return - Symfony\Contracts\HttpClient\ResponseInterface - /Services - /CRM - /Deals - /Client - Deals.php - /Exceptions - /Tasks - … - Main.php - default bitrix24 rest api service provide basic funcions, work with data transfer objects -``` - ### Requirements -- php: >=7.4 +- php: >=8.2 - ext-json: * - ext-curl: * -### Example - ### Installation Add `"mesilov/bitrix24-php-sdk": "2.x"` to `composer.json` of your application. Or clone repo to your project. @@ -198,194 +156,24 @@ email: [Register new Bitrix24 account](https://www.bitrix24.ru/create.php?p=255670) -## Русский - -### Принципы по которым ведётся разработка - -- хороший DX (Developer Experience) - - автодополнение методов на уровне IDE - - типизированные сигнатуры вызова методов - - типизированные результаты вызова методов – используются нативные типы: int, array, bool, string - - хелперы для типовых операций -- хорошая документация - - документация по работе конкретного метода содержащая ссылку на офф документацию - - документация по работе с SDK -- производительность: - - минимальное влияние на клиентский код - - возможность работать с большими объёмами данных с константным потреблением памяти - - эффективная работа c API с использованием батч-запросов -- современный стек технологий: - - библиотеки для работы с сетью и возможностью асинхронной работы - - фичи новых версий PHP -- надёжной: - - покрытие тестами: unit, интеграционные, контрактные - - есть типовые примеры характерные для разных режимов работы и они оптимизированы по памяти \ быстродействию - -### Спонсоры - -Помогите развитию bitrix24-php-sdk подписавшись на [boosty.to/bitrix24-php-sdk](https://boosty.to/bitrix24-php-sdk)! - -### Ключевые особенности - -### Слои SDK - -### Service – API-интерфейс для работы с конкретной сущностью - -Зона ответственности: - -- контракт на API-методы сущности - -Входящие данные: - -- сигнатура вызова конкретного API-метода - -Возвращаемый результат: - -- `Core\Response` (????) **к обсуждению** - -В зависимости от метода может быть разный возвращаемый результат: - -- результат выполнения операции типа bool -- идентификатор созданной сущности типа int -- сущность + пользовательские поля с префиксами UF_ типа array -- массив сущностей типа array -- пустой массив как результат пустого фильтра. - -Если возвращать `Core\Response`, то в клиентском коде будут проблемы: - -- длинные цепочки в клиентском коде для получения возвращаемого результата - -```php -// добавили сделку в Б24 -$dealId = $dealsService->add($newDeal)->getResponseData()->getResult()->getResultData()[0]; -// получили массив сделок -$deals = $dealsService->list([], [], [], 0)->getResponseData()->getResult()->getResultData(); -``` - -- отсутствие релевантной вызываемому методу типизации возвращаемого результата. - -Ожидание: - -```php - add(array $newDeal):int // идентификатор новой сделки - list(array $order, array $filter, array $select, int $start):array //массив сделок + постраничка - get(int $dealId):array // конкретная сделка -``` - -Текущая реализация — возвращается унифицированный результат: - -```php -add(array $newDeal):Core\Response -list(array $order, array $filter, array $select, int $start):Core\Response -``` - -#### Core – вызов произвольных API-методов - -Зона ответственности: - -- вызов **произвольных** API-методов -- обработка ошибок уровня API -- запрос нового токена и повторение запроса, если получили ошибку `expired_token` - -Входящие данные: - -- `string $apiMethod` – название api-метода -- `array $parameters = []` – аргументы метода -Возвращаемый результат: `Core\Response` – **унифицированный** объект-обёртка, содержит: - -- `Symfony\Contracts\HttpClient\ResponseInterface` — объект ответа от сервера, может быть асинхронным -- `Core\Commands\Command` — информация о команде\аргументах которая была исполнена, используется при разборе пакетных запросов. - -Для получения результата запроса к API используется метод `Response::getResponseData`, который декодирует тело ответа вызвав -метод `Symfony\Contracts\HttpClient::toArray` -Возвращается стандартизированный DTO `ResponseData` от API-сервера с полями: - -- `Result` - DTO c результатом исполнения запроса; -- `Time` — DTO c таймингом прохождения запроса через сервера Битрикс24; -- `Pagination` — DTO постраничной навигации с полями `next` и `total`; - -В случае обнаружения ошибок уровня домена будет выброшено соответствующее типизированное исключение. - -Объект `Result` содержит метод `getResultData`, который возвращает массив с результатом исполнения API-запроса. В зависимости от вызванного -метода там может быть: - -- результат выполнения операции типа bool -- идентификатор созданной сущности типа int -- сущность + пользовательские поля с префиксами UF_ типа array -- массив сущностей типа array -- пустой массив как результат пустого фильтра. - -#### ApiClient — работа с сетью и эндпоинтами API-серверов - -Зона ответственности: - -- передача данных по сети -- соблюдение контракта на эндпоинты с которыми идёт работы -- «подпись» запросов токенами \ передача их в нужные входящие адреса если используется авторизация по вебхукам - -Используется: -Symfony HttpClient - -Входящие данные: - -- тип http-запроса -- массив с параметрами - -Возвращаемые результаты: -— `Symfony\Contracts\HttpClient\ResponseInterface` - -#### Формат передачи данных по сети - -JSON по HTTP/2 или HTTP/1.1 - -## Спонсоры - -### Тесты - -Тесты расположены в папке `tests` и бывают двух типов: юнит и интеграционные. -В папке `tests` создайте файл `.env.local` и заполните переменные из файла `.env`. - -#### Юнит тесты - -**Быстрые**, выполняются без сетевого взаимодействия с Битрикс 24. - -```shell -composer phpunit-run-unit-test -``` - -#### Интеграционные тесты - -**Медленные** тесты покрывают полный жизненный цикл CRUD операций подключение к Битрикс 24 происходи с помощью веб-хука. - -❗ Не запускайте интеграционные тесты на ваших production порталах они удалят все ваши данные ❗️ - -Для запуска интеграционных тестов вам нужно: - -1. Создать [Новый портал Битрикс 24](https://www.bitrix24.ru/create.php?p=255670) для запуска тестов. -2. Перейти в левое меню и нажать "Карта сайта". -3. Найти меню для "Разработчиков" -4. Кликнуть в меню «Другое» -5. Кликнуть в меню «Входящий веб-хук» -6. Выбрать все нужные расширения и нажать кнопку "сохранить". -7. Создать файл `/tests/.env.local` с переменными окружения которые скопировать из файла `/tests/.env` . - -```yaml -APP_ENV=dev -BITRIX24_WEBHOOK=https:// your portal webhook url -INTEGRATION_TEST_LOG_LEVEL=500 -``` +### Architecture -8. Запуск из командной строки. +#### Abstraction layers -```shell -composer composer phpunit-run-integration-tests ``` - -#### Статический анализ кодовой базы – phpstan - -Запуск из командной строки. - -```shell - composer phpstan-analyse +- http protocol +- json data +- symfony http client +- \Bitrix24\SDK\Core\ApiClient - work with b24 rest-api endpoints + input: arrays \ strings + output: Symfony\Contracts\HttpClient\ResponseInterface, operate with strings + process: network operations +- \Bitrix24\SDK\Services\* - work with b24 rest-api entities + input: arrays \ strings + output: b24 response dto + process: b24 entities, operate with immutable objects ``` +#### Symfony HttpClient +#### Core +#### ApiClient diff --git a/composer.json b/composer.json index c6cf5d7c..0aba0659 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "sort-packages": true }, "require": { - "php": "8.3.*", + "php": "8.2.* || 8.3.*", "ext-json": "*", "ext-bcmath": "*", "ext-curl": "*", From e649a3ca35f1445819e4679724d477b8738d43d5 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 18 Feb 2024 22:48:28 +0600 Subject: [PATCH 499/647] Add catalog service functions and product service methods to SDK This update adds new catalog service-related functions in the CatalogServiceBuilder file and introduces several methods for product service. These methods include functions to add, delete, and retrieve products. Additionally, several integration tests have been introduced to ensure the correct functioning of these new methods. Also, an example phpstan static analyzer command's been added to Makefile, and PHP requirement has been adjusted to support PHP 8.2. Plus, the README file has been refactored for clarity and better organization. Signed-off-by: mesilov --- Makefile | 6 + README.md | 93 +++++----- .../Catalog/Result/CatalogItemResult.php | 23 +++ .../Catalog/Catalog/Result/CatalogResult.php | 15 ++ .../Catalog/Catalog/Result/CatalogsResult.php | 26 +++ .../Catalog/Catalog/Service/Catalog.php | 64 +++++++ .../Catalog/CatalogServiceBuilder.php | 13 ++ .../Product/Result/ProductItemResult.php | 11 -- .../Catalog/Product/Result/ProductResult.php | 4 + .../Catalog/Product/Service/Product.php | 39 ++++- .../Catalog/Catalog/Service/CatalogTest.php | 62 +++++++ .../Catalog/Product/Service/ProductTest.php | 159 ++++++++++++++++++ 12 files changed, 452 insertions(+), 63 deletions(-) create mode 100644 Makefile create mode 100644 src/Services/Catalog/Catalog/Result/CatalogItemResult.php create mode 100644 src/Services/Catalog/Catalog/Result/CatalogResult.php create mode 100644 src/Services/Catalog/Catalog/Result/CatalogsResult.php create mode 100644 src/Services/Catalog/Catalog/Service/Catalog.php create mode 100644 tests/Integration/Services/Catalog/Catalog/Service/CatalogTest.php create mode 100644 tests/Integration/Services/Catalog/Product/Service/ProductTest.php diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..ee1097e7 --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ +default: + @echo "make needs target:" + @egrep -e '^\S+' ./Makefile | grep -v default | sed -r 's/://' | sed -r 's/^/ - /' + +phpstan: + vendor/bin/phpstan analyse \ No newline at end of file diff --git a/README.md b/README.md index 27a56e2c..162cf165 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Bitrix24 REST API PHP SDK A powerful PHP library for the Bitrix24 REST API -### Build status +## Build status | CI\CD [status](https://github.com/mesilov/bitrix24-php-sdk/actions) on `master` | |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| @@ -15,20 +15,16 @@ A powerful PHP library for the Bitrix24 REST API Integration tests run in GitHub actions with real Bitrix24 portal -### BITRIX24-PHP-SDK ✨FEATURES✨ +## BITRIX24-PHP-SDK ✨FEATURES✨ Support both auth modes: - [x] work with auth tokens for Bitrix24 applications in marketplace - [x] work with incoming webhooks for simple integration projects for current portal -Low-level tools to devs: - -- Domain core events: - - [x] Access Token expired - - [ ] Bitrix24 portal domain url changed -- [ ] Rate-limit strategy -- [ ] Retry strategy for safe methods +Domain core events: + - [x] Access Token expired + - [x] Bitrix24 portal domain url changed API - level features @@ -46,7 +42,12 @@ Performance improvements 🚀 - [ ] composite batch queries to many entities (work in progress) - [ ] read without count flag -### Development principles +Low-level tools to devs: +- [ ] Rate-limit strategy +- [ ] Retry strategy for safe methods + + +## Development principles - Good developer experience - auto-completion of methods at the IDE @@ -67,26 +68,42 @@ Performance improvements 🚀 - test coverage: unit, integration, contract - typical examples typical for different modes of operation and they are optimized for memory \ performance -### Sponsors +## Architecture -Help bitrix24-php-sdk by [boosty.to/bitrix24-php-sdk](https://boosty.to/bitrix24-php-sdk) its development! +### Abstraction layers -### Requirements +``` +- http2 protocol via json data structures +- symfony http client +- \Bitrix24\SDK\Core\ApiClient - work with b24 rest-api endpoints + input: arrays \ strings + output: Symfony\Contracts\HttpClient\ResponseInterface, operate with strings + process: network operations +- \Bitrix24\SDK\Services\* - work with b24 rest-api entities + input: arrays \ strings + output: b24 response dto + process: b24 entities, operate with immutable objects +``` +## Sponsors + +Help bitrix24-php-sdk by [boosty.to/bitrix24-php-sdk](https://boosty.to/bitrix24-php-sdk) + +## Requirements - php: >=8.2 - ext-json: * - ext-curl: * -### Installation +## Installation Add `"mesilov/bitrix24-php-sdk": "2.x"` to `composer.json` of your application. Or clone repo to your project. -### Tests +## 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`. -#### Unit tests +### Unit tests **Fast**, in-memory tests without a network I\O For run unit tests you must call in command line @@ -94,11 +111,11 @@ In folder tests create file `.env.local` and fill environment variables from `.e composer phpunit-run-unit-test ``` -#### Integration tests +### Integration tests **Slow** tests with full lifecycle with your **test** Bitrix24 portal via webhook. -❗️Do not run integration tests with production portals ❗️ +❗️Do not run integration tests with production portals For run integration test you must: @@ -130,50 +147,28 @@ Call in command line composer phpstan-analyse ``` -### Submitting bugs and feature requests +## Submitting bugs and feature requests Bugs and feature request are tracked on [GitHub](https://github.com/mesilov/bitrix24-php-sdk/issues) -### License +## License bitrix24-php-sdk is licensed under the MIT License - see the `MIT-LICENSE.txt` file for details -### Author +## Authors -Maxim Mesilov - -
-See also the list of [contributors](https://github.com/mesilov/bitrix24-php-sdk/graphs/contributors) which participated in this project. +Maksim Mesilov - mesilov.maxim@gmail.com -### Need custom Bitrix24 application? ## +See also the list of [contributors](https://github.com/mesilov/bitrix24-php-sdk/graphs/contributors) which participated in this project. -email: +## Need custom Bitrix24 application? +mesilov.maxim@gmail.com for private consultations or dedicated support -### Documentation +## 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) - - -### Architecture - -#### Abstraction layers - -``` -- http protocol -- json data -- symfony http client -- \Bitrix24\SDK\Core\ApiClient - work with b24 rest-api endpoints - input: arrays \ strings - output: Symfony\Contracts\HttpClient\ResponseInterface, operate with strings - process: network operations -- \Bitrix24\SDK\Services\* - work with b24 rest-api entities - input: arrays \ strings - output: b24 response dto - process: b24 entities, operate with immutable objects -``` -#### Symfony HttpClient -#### Core -#### ApiClient +[Register new Bitrix24 account](https://www.bitrix24.ru/create.php?p=255670) \ No newline at end of file diff --git a/src/Services/Catalog/Catalog/Result/CatalogItemResult.php b/src/Services/Catalog/Catalog/Result/CatalogItemResult.php new file mode 100644 index 00000000..7a406f88 --- /dev/null +++ b/src/Services/Catalog/Catalog/Result/CatalogItemResult.php @@ -0,0 +1,23 @@ +getCoreResponse()->getResponseData()->getResult()['catalog']); + } +} \ No newline at end of file diff --git a/src/Services/Catalog/Catalog/Result/CatalogsResult.php b/src/Services/Catalog/Catalog/Result/CatalogsResult.php new file mode 100644 index 00000000..44c9799d --- /dev/null +++ b/src/Services/Catalog/Catalog/Result/CatalogsResult.php @@ -0,0 +1,26 @@ +getCoreResponse()->getResponseData()->getResult()['catalogs'] as $product) { + $res[] = new ProductItemResult($product); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/Catalog/Catalog/Service/Catalog.php b/src/Services/Catalog/Catalog/Service/Catalog.php new file mode 100644 index 00000000..b09c7e61 --- /dev/null +++ b/src/Services/Catalog/Catalog/Service/Catalog.php @@ -0,0 +1,64 @@ +core->call('catalog.catalog.get', ['id' => $catalogId])); + } + + /** + * The method gets field value of commercial catalog product by ID. + * + * @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 + */ + public function list(array $select, array $filter, array $order, int $start): CatalogsResult + { + return new CatalogsResult($this->core->call('catalog.catalog.list', [ + 'select' => $select, + 'filter' => $filter, + 'order' => $order, + 'start' => $start + ])); + } + + /** + * Retrieves the fields for the catalog. + * + * @return FieldsResult Returns an instance of FieldsResult. + * @throws BaseException Throws a BaseException if there is an error in the core call. + * @throws TransportException Throws a TransportException if there is an error in the transport process. + * @see https://training.bitrix24.com/rest_help/catalog/catalog/catalog_catalog_getfields.php + */ + public function fields(): FieldsResult + { + return new FieldsResult($this->core->call('catalog.catalog.getFields')); + } +} \ No newline at end of file diff --git a/src/Services/Catalog/CatalogServiceBuilder.php b/src/Services/Catalog/CatalogServiceBuilder.php index 108db59d..32347b8c 100644 --- a/src/Services/Catalog/CatalogServiceBuilder.php +++ b/src/Services/Catalog/CatalogServiceBuilder.php @@ -6,6 +6,7 @@ use Bitrix24\SDK\Services\AbstractServiceBuilder; use Bitrix24\SDK\Services\Catalog; + class CatalogServiceBuilder extends AbstractServiceBuilder { public function product(): Catalog\Product\Service\Product @@ -20,4 +21,16 @@ public function product(): Catalog\Product\Service\Product return $this->serviceCache[__METHOD__]; } + + public function catalog(): Catalog\Catalog\Service\Catalog + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Catalog\Catalog\Service\Catalog( + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } } \ No newline at end of file diff --git a/src/Services/Catalog/Product/Result/ProductItemResult.php b/src/Services/Catalog/Product/Result/ProductItemResult.php index 475c4bff..07349bb3 100644 --- a/src/Services/Catalog/Product/Result/ProductItemResult.php +++ b/src/Services/Catalog/Product/Result/ProductItemResult.php @@ -6,7 +6,6 @@ use Bitrix24\SDK\Services\Catalog\Common\ProductType; use Bitrix24\SDK\Services\Catalog\Common\Result\AbstractCatalogItem; -use Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNotFoundException; use DateTimeInterface; use Money\Currency; use Money\Money; @@ -44,14 +43,4 @@ */ class ProductItemResult extends AbstractCatalogItem { - /** - * @param string $userfieldName - * - * @return mixed|null - * @throws UserfieldNotFoundException - */ - public function getUserfieldByFieldName(string $userfieldName) - { - return $this->getKeyWithUserfieldByFieldName($userfieldName); - } } \ No newline at end of file diff --git a/src/Services/Catalog/Product/Result/ProductResult.php b/src/Services/Catalog/Product/Result/ProductResult.php index 3e5564fe..e9aef70e 100644 --- a/src/Services/Catalog/Product/Result/ProductResult.php +++ b/src/Services/Catalog/Product/Result/ProductResult.php @@ -10,6 +10,10 @@ class ProductResult extends AbstractResult { public function product(): ProductItemResult { + if (array_key_exists('element', $this->getCoreResponse()->getResponseData()->getResult())) { + // fix for catalog.product.add + return new ProductItemResult($this->getCoreResponse()->getResponseData()->getResult()['element']); + } return new ProductItemResult($this->getCoreResponse()->getResponseData()->getResult()['product']); } } \ No newline at end of file diff --git a/src/Services/Catalog/Product/Service/Product.php b/src/Services/Catalog/Product/Service/Product.php index c7c6e928..afb59635 100644 --- a/src/Services/Catalog/Product/Service/Product.php +++ b/src/Services/Catalog/Product/Service/Product.php @@ -4,21 +4,22 @@ namespace Bitrix24\SDK\Services\Catalog\Product\Service; - use Bitrix24\SDK\Core\Contracts\CoreInterface; use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Exceptions\TransportException; -use Bitrix24\SDK\Core\Response\Response; +use Bitrix24\SDK\Core\Result\DeletedItemResult; use Bitrix24\SDK\Core\Result\FieldsResult; use Bitrix24\SDK\Services\AbstractService; use Bitrix24\SDK\Services\Catalog\Common\ProductType; -use Bitrix24\SDK\Services\Catalog\Product\Result\ProductItemResult; use Bitrix24\SDK\Services\Catalog\Product\Result\ProductResult; use Bitrix24\SDK\Services\Catalog\Product\Result\ProductsResult; + use Psr\Log\LoggerInterface; class Product extends AbstractService { + public Batch $batch; + public function __construct( Batch $batch, CoreInterface $core, @@ -26,6 +27,7 @@ public function __construct( ) { parent::__construct($core, $log); + $this->batch = $batch; } /** @@ -40,6 +42,37 @@ public function get(int $productId): ProductResult return new ProductResult($this->core->call('catalog.product.get', ['id' => $productId])); } + /** + * The method adds a commercial catalog product. + * + * @see https://training.bitrix24.com/rest_help/catalog/product/catalog_product_add.php + * @param array $productFields + * @return ProductResult + * @throws BaseException + * @throws TransportException + */ + public function add(array $productFields): ProductResult + { + return new ProductResult($this->core->call('catalog.product.add', [ + 'fields' => $productFields + ] + )); + } + + /** + * The method deletes commercial catalog product. + * + * @see https://training.bitrix24.com/rest_help/catalog/product/catalog_product_delete.php + * @param int $productId + * @return DeletedItemResult + * @throws BaseException + * @throws TransportException + */ + public function delete(int $productId): DeletedItemResult + { + return new DeletedItemResult($this->core->call('catalog.product.delete', ['id' => $productId])); + } + /** * The method gets list of commercial catalog products by filter. * diff --git a/tests/Integration/Services/Catalog/Catalog/Service/CatalogTest.php b/tests/Integration/Services/Catalog/Catalog/Service/CatalogTest.php new file mode 100644 index 00000000..dc106b5b --- /dev/null +++ b/tests/Integration/Services/Catalog/Catalog/Service/CatalogTest.php @@ -0,0 +1,62 @@ +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 + */ + 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 + */ + 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 + { + $this->service = Fabric::getServiceBuilder()->getCatalogScope()->catalog(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/Catalog/Product/Service/ProductTest.php b/tests/Integration/Services/Catalog/Product/Service/ProductTest.php new file mode 100644 index 00000000..5628390e --- /dev/null +++ b/tests/Integration/Services/Catalog/Product/Service/ProductTest.php @@ -0,0 +1,159 @@ +catalogService->list([], [], [], 1)->getCatalogs()[0]->iblockId; + $this->assertIsArray($this->productService->fieldsByFilter( + $iblockId, + ProductType::simple + )->getFieldsDescription()); + } + + /** + * 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() + */ + public function testAdd(): void + { + $iblockId = $this->catalogService->list([], [], [], 1)->getCatalogs()[0]->iblockId; + $fields = [ + 'iblockId' => $iblockId, + '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); + } + + /** + * 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() + */ + public function testGet(): void + { + $iblockId = $this->catalogService->list([], [], [], 1)->getCatalogs()[0]->iblockId; + $fields = [ + '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); + $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 + */ + public function testDelete(): void + { + $iblockId = $this->catalogService->list([], [], [], 1)->getCatalogs()[0]->iblockId; + $fields = [ + '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); + $this->productService->delete($productGet->product()->id); + + $filteredProducts = $this->productService->list( + [ + 'id', + 'iblockId' + ], + [ + 'id' => $productGet->product()->id, + 'iblockId' => $iblockId + ], + [ + 'id' => 'asc' + ], + 1 + ); + $this->assertCount(0, $filteredProducts->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() + */ + public function testList():void + { + $iblockId = $this->catalogService->list([], [], [], 1)->getCatalogs()[0]->iblockId; + $fields = [ + '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( + [ + 'id', + 'iblockId' + ], + [ + 'id' => $productGet->product()->id, + 'iblockId' => $iblockId + ], + [ + 'id' => 'asc' + ], + 1 + ); + $this->assertCount(1, $filteredProducts->getProducts()); + } + + public function setUp(): void + { + $this->productService = Fabric::getServiceBuilder()->getCatalogScope()->product(); + $this->catalogService = Fabric::getServiceBuilder()->getCatalogScope()->catalog(); + } +} \ No newline at end of file From ad94742e9ccfc3f7ce64f946af99fbc30bb447b0 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 18 Feb 2024 23:04:24 +0600 Subject: [PATCH 500/647] Change data provider methods to static in tests The data provider methods used in various test cases have been changed to static. This change was applied to "CredentialsTest", "ApplicationStatusTest", "ApplicationProfileTest", "DefaultRequestIdGeneratorTest", and "TimeTest". An additional command has also been added to the Makefile for running unit tests. Signed-off-by: mesilov --- Makefile | 5 ++++- tests/Unit/Application/ApplicationStatusTest.php | 2 +- tests/Unit/Core/Credentials/ApplicationProfileTest.php | 2 +- tests/Unit/Core/Credentials/CredentialsTest.php | 2 +- tests/Unit/Core/Response/DTO/TimeTest.php | 2 +- .../HttpClient/RequestId/DefaultRequestIdGeneratorTest.php | 2 +- 6 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index ee1097e7..6e31904d 100644 --- a/Makefile +++ b/Makefile @@ -3,4 +3,7 @@ default: @egrep -e '^\S+' ./Makefile | grep -v default | sed -r 's/://' | sed -r 's/^/ - /' phpstan: - vendor/bin/phpstan analyse \ No newline at end of file + vendor/bin/phpstan analyse + +test-unit: + vendor/bin/phpunit --testsuite unit_tests \ No newline at end of file diff --git a/tests/Unit/Application/ApplicationStatusTest.php b/tests/Unit/Application/ApplicationStatusTest.php index d768b0e4..ba6214ce 100644 --- a/tests/Unit/Application/ApplicationStatusTest.php +++ b/tests/Unit/Application/ApplicationStatusTest.php @@ -49,7 +49,7 @@ public function testInitFromString(): void /** * @return \Generator */ - public function statusDataProvider(): Generator + public static function statusDataProvider(): Generator { yield 'free' => [ 'F', diff --git a/tests/Unit/Core/Credentials/ApplicationProfileTest.php b/tests/Unit/Core/Credentials/ApplicationProfileTest.php index 17956aac..27d415f7 100644 --- a/tests/Unit/Core/Credentials/ApplicationProfileTest.php +++ b/tests/Unit/Core/Credentials/ApplicationProfileTest.php @@ -31,7 +31,7 @@ public function testFromArray(array $arr, ?string $expectedException): void $this->assertEquals($prof->getClientSecret(), $arr['BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET']); } - public function arrayDataProvider(): Generator + public static function arrayDataProvider(): Generator { yield 'valid' => [ [ diff --git a/tests/Unit/Core/Credentials/CredentialsTest.php b/tests/Unit/Core/Credentials/CredentialsTest.php index 5d3ccfdb..64438eef 100644 --- a/tests/Unit/Core/Credentials/CredentialsTest.php +++ b/tests/Unit/Core/Credentials/CredentialsTest.php @@ -70,7 +70,7 @@ public function testDomainUrlWithProtocol(): void * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException * @throws \Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException */ - public function credentialsDataProviderWithDomainUrlVariants(): Generator + public static function credentialsDataProviderWithDomainUrlVariants(): Generator { yield 'with webhook walid domain url' => [ Credentials::createFromWebhook(new WebhookUrl('https://bitrix24-php-sdk-playground.bitrix24.ru/rest/1/valid-webhook/')), diff --git a/tests/Unit/Core/Response/DTO/TimeTest.php b/tests/Unit/Core/Response/DTO/TimeTest.php index 64f597b2..99a7db9d 100644 --- a/tests/Unit/Core/Response/DTO/TimeTest.php +++ b/tests/Unit/Core/Response/DTO/TimeTest.php @@ -36,7 +36,7 @@ public function testInitFromResponseData(array $result): void /** * @return \Generator */ - public function timingsDataProvider(): Generator + public static function timingsDataProvider(): Generator { yield 'without operating reset at' => [ [ diff --git a/tests/Unit/Infrastructure/HttpClient/RequestId/DefaultRequestIdGeneratorTest.php b/tests/Unit/Infrastructure/HttpClient/RequestId/DefaultRequestIdGeneratorTest.php index fab333b8..48b21e52 100644 --- a/tests/Unit/Infrastructure/HttpClient/RequestId/DefaultRequestIdGeneratorTest.php +++ b/tests/Unit/Infrastructure/HttpClient/RequestId/DefaultRequestIdGeneratorTest.php @@ -26,7 +26,7 @@ public function testExistsRequestId($requestIdKey, $requestId): void unset($_SERVER[$requestIdKey]); } - public function requestIdKeyDataProvider(): Generator + public static function requestIdKeyDataProvider(): Generator { yield 'REQUEST_ID' => [ 'REQUEST_ID', From 6aeacd6f96fd3edf0bdd3471b569d9b5d2d0b82c Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 18 Feb 2024 23:13:29 +0600 Subject: [PATCH 501/647] Refactor constants declaration in DefaultRequestIdGenerator Constants in DefaultRequestIdGenerator were refactored to remove 'string' and 'array' type declarations. These changes conform to PHP constants declaration rules, which do not require type specification. Signed-off-by: mesilov --- .../HttpClient/RequestId/DefaultRequestIdGenerator.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Infrastructure/HttpClient/RequestId/DefaultRequestIdGenerator.php b/src/Infrastructure/HttpClient/RequestId/DefaultRequestIdGenerator.php index 9b49016d..84defcd0 100644 --- a/src/Infrastructure/HttpClient/RequestId/DefaultRequestIdGenerator.php +++ b/src/Infrastructure/HttpClient/RequestId/DefaultRequestIdGenerator.php @@ -8,9 +8,9 @@ class DefaultRequestIdGenerator implements RequestIdGeneratorInterface { - private const string DEFAULT_REQUEST_ID_HEADER_FIELD_NAME = 'X-Request-ID'; - private const string DEFAULT_QUERY_STRING_PARAMETER_NAME = 'bx24_request_id'; - private const array KEY_NAME_VARIANTS = [ + private const DEFAULT_REQUEST_ID_HEADER_FIELD_NAME = 'X-Request-ID'; + private const DEFAULT_QUERY_STRING_PARAMETER_NAME = 'bx24_request_id'; + private const KEY_NAME_VARIANTS = [ 'REQUEST_ID', 'HTTP_X_REQUEST_ID', 'UNIQUE_ID' From 86f088537301f2190907c09acfbad3cd6e670ae9 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 18 Feb 2024 23:15:39 +0600 Subject: [PATCH 502/647] Update constant declaration in AbstractCrmItem The constant CRM_USERFIELD_PREFIX in the AbstractCrmItem class has been updated to remove the 'string' type declaration, in accordance with PHP's constants declaration rules which do not require specifying the type. Signed-off-by: mesilov --- src/Services/CRM/Common/Result/AbstractCrmItem.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Services/CRM/Common/Result/AbstractCrmItem.php b/src/Services/CRM/Common/Result/AbstractCrmItem.php index f7d9c321..84ffb151 100644 --- a/src/Services/CRM/Common/Result/AbstractCrmItem.php +++ b/src/Services/CRM/Common/Result/AbstractCrmItem.php @@ -17,7 +17,7 @@ class AbstractCrmItem extends AbstractItem { - private const string CRM_USERFIELD_PREFIX = 'UF_CRM_'; + private const CRM_USERFIELD_PREFIX = 'UF_CRM_'; /** * @var Currency From 855cd960b7193e19c2df05326cb980f0d1152323 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 18 Feb 2024 23:17:22 +0600 Subject: [PATCH 503/647] Update constant declaration in AbstractCatalogItem The constant CRM_USERFIELD_PREFIX in the AbstractCatalogItem class has been updated to remove the 'string' type declaration, keeping in line with PHP's convention for declaring constants which does not require specifying the type. Signed-off-by: mesilov --- src/Services/Catalog/Common/Result/AbstractCatalogItem.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Services/Catalog/Common/Result/AbstractCatalogItem.php b/src/Services/Catalog/Common/Result/AbstractCatalogItem.php index 435beeb4..b1d0138a 100644 --- a/src/Services/Catalog/Common/Result/AbstractCatalogItem.php +++ b/src/Services/Catalog/Common/Result/AbstractCatalogItem.php @@ -13,7 +13,7 @@ abstract class AbstractCatalogItem extends AbstractItem { - private const string CRM_USERFIELD_PREFIX = 'UF_CRM_'; + private const CRM_USERFIELD_PREFIX = 'UF_CRM_'; /** * @var Currency From bad9929eae5d3df471cdfdcf4c4ca05603c8f5b7 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 18 Feb 2024 23:19:58 +0600 Subject: [PATCH 504/647] Update release date and php support in CHANGELOG The release date for version 2.0-beta.1 in the CHANGELOG.md file has been updated. Additionally, the PHP support information has also been changed to reflect the added support for PHP 8.2 and 8.3, and the removal of support for PHP 8.0 and 8.1. Signed-off-by: mesilov --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e31e28c0..7c8ad878 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,10 @@ # bitrix24-php-sdk change log -## 2.0-beta.1 — 25.03.2023 +## 2.0-beta.1 — 18.02.2024 ### Added -* ❗️add php 8.3 support, drop 8.1 and 8.0 support +* ❗️add php 8.3, 8.2 support, drop 8.1 and 8.0 support * add `Symfony\Component\Uid\Uuid` requirements * add contracts for bitrix24 applications based on bitrix24-php-sdk - `Bitrix24\SDK\Application\Contracts`, now added `Bitrix24Account` From 0ff10141681df582addf96ff10a78efc97ea3ac3 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 14 Mar 2024 02:50:06 +0600 Subject: [PATCH 505/647] Update dependency versions in composer.json The versions of several dependencies in the composer.json file have been updated. This applies to both the main requirements and the development requirements. The upgrades ensure compatibility with the latest versions, improving overall functionality and performance. Signed-off-by: mesilov --- CHANGELOG.md | 14 ++++++++++++++ composer.json | 8 ++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c8ad878..20495c42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # bitrix24-php-sdk change log +## 2.0-beta.2 — 1.04.2024 + +### Added +### 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.*` +### Bugfix +### etc + ## 2.0-beta.1 — 18.02.2024 ### Added diff --git a/composer.json b/composer.json index 0aba0659..4081f549 100644 --- a/composer.json +++ b/composer.json @@ -25,10 +25,10 @@ "ext-bcmath": "*", "ext-curl": "*", "ext-intl": "*", - "psr/log": "1.1.*", + "psr/log": "3.0.*", "fig/http-message-util": "1.1.*", "ramsey/uuid": "4.7.*", - "moneyphp/money": "4.3.*", + "moneyphp/money": "4.5.*", "symfony/http-client": "7.0.*", "symfony/http-client-contracts": "3.4.*", "symfony/http-foundation": "7.0.*", @@ -36,9 +36,9 @@ "symfony/uid": "7.0.*" }, "require-dev": { - "monolog/monolog": "2.9.*", + "monolog/monolog": "3.5.*", "phpstan/phpstan": "1.10.*", - "phpunit/phpunit": "10.5.*", + "phpunit/phpunit": "11.0.*", "symfony/console": "7.0.*", "symfony/dotenv": "7.0.*", "symfony/debug-bundle": "7.0.*", From f55436411c7cacc3e7b47ad131b02362b3e34b3c Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 31 Mar 2024 19:42:23 +0600 Subject: [PATCH 506/647] Add webhook example for bitrix24-php-sdk This commit introduces an example of how to use bitrix24-php-sdk with webhooks. It includes the configuration needed to set up the SDK with a webhook URL, and an example of how to fetch and display information about a deal. Additionally, a task in the README.md file has been marked as complete. Signed-off-by: mesilov --- .gitignore | 1 + README.md | 27 +++++++++++++++++++++++++-- examples/webhook/.env | 5 +++++ examples/webhook/composer.json | 20 ++++++++++++++++++++ examples/webhook/example.php | 30 ++++++++++++++++++++++++++++++ 5 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 examples/webhook/.env create mode 100644 examples/webhook/composer.json create mode 100644 examples/webhook/example.php diff --git a/.gitignore b/.gitignore index f5140f0e..6ae5ed5a 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ composer.lock tools/.env.local tools/logs examples/logs +*.log .env.local \ No newline at end of file diff --git a/README.md b/README.md index 162cf165..1b68984d 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Domain core events: API - level features - [x] Auto renew access tokens -- [ ] List queries with «start=-1» support +- [x] List queries with «start=-1» support - [ ] offline queues Performance improvements 🚀 @@ -67,7 +67,6 @@ 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 @@ -98,6 +97,30 @@ 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); + +use Bitrix24\SDK\Services\ServiceBuilderFactory; +use Monolog\Logger; +use Symfony\Component\EventDispatcher\EventDispatcher; + +require_once 'vendor/autoload.php'; + +$webhookUrl = 'INSERT_HERE_YOUR_WEBHOOK_URL'; + +$log = new Logger('bitrix24-php-sdk'); +$b24ServiceFactory = new ServiceBuilderFactory(new EventDispatcher(), $log); + +// init bitrix24-php-sdk service +$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); +``` + ## Tests Tests locate in folder `tests` and we have two test types. diff --git a/examples/webhook/.env b/examples/webhook/.env new file mode 100644 index 00000000..1355fb8e --- /dev/null +++ b/examples/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/webhook/composer.json b/examples/webhook/composer.json new file mode 100644 index 00000000..03105bc5 --- /dev/null +++ b/examples/webhook/composer.json @@ -0,0 +1,20 @@ +{ + "name": "mesilov/bitrix24-php-sdk-webhook-example", + "description": "Example for work with bitrix24-php-sdk via webhook", + "minimum-stability": "stable", + "license": "proprietary", + "authors": [ + { + "name": "Maksim Mesilov", + "email": "mesilov.maxim@gmail.com" + } + ], + "require": { + "mesilov/bitrix24-php-sdk": "dev-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/webhook/example.php b/examples/webhook/example.php new file mode 100644 index 00000000..bc3098ac --- /dev/null +++ b/examples/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 From 7acaf7a1dfee02f35342be01a63cebfed8aa35ed Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 1 Apr 2024 02:23:27 +0600 Subject: [PATCH 507/647] 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 508/647] 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 509/647] 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 510/647] 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: Thu, 11 Apr 2024 20:19:07 +0600 Subject: [PATCH 511/647] Update version constraints in composer.json The commit updates the version constraints for multiple packages in composer.json, making them more flexible by allowing both current and one previous major version. This should ease package updates and compatibility issues in the future. Signed-off-by: mesilov --- composer.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index 4081f549..18458c2f 100644 --- a/composer.json +++ b/composer.json @@ -25,15 +25,15 @@ "ext-bcmath": "*", "ext-curl": "*", "ext-intl": "*", - "psr/log": "3.0.*", + "psr/log": "^2 || ˆ3", "fig/http-message-util": "1.1.*", - "ramsey/uuid": "4.7.*", - "moneyphp/money": "4.5.*", - "symfony/http-client": "7.0.*", - "symfony/http-client-contracts": "3.4.*", - "symfony/http-foundation": "7.0.*", - "symfony/event-dispatcher": "7.0.*", - "symfony/uid": "7.0.*" + "ramsey/uuid": "^3 ||^4", + "moneyphp/money": "^3 || ^4", + "symfony/http-client": "^6 || ^7", + "symfony/http-client-contracts": "^2 || ^3", + "symfony/http-foundation": "^6 || ^7", + "symfony/event-dispatcher": "^6 || ^7", + "symfony/uid": "^6 || ^7" }, "require-dev": { "monolog/monolog": "3.5.*", From a4c5246f28f3c11ad6a211c5c7ce971edc7c6c89 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 11 Apr 2024 20:20:09 +0600 Subject: [PATCH 512/647] Fix typo in psr/log version constraint in composer.json The typo in the version constraint for the psr/log dependency in the composer.json file has been corrected. This revision ensures the correct versions (^2 or ^3) of the Signed-off-by: mesilov --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 18458c2f..4d19c130 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ "ext-bcmath": "*", "ext-curl": "*", "ext-intl": "*", - "psr/log": "^2 || ˆ3", + "psr/log": "^2 || ^3", "fig/http-message-util": "1.1.*", "ramsey/uuid": "^3 ||^4", "moneyphp/money": "^3 || ^4", From acb3775bf3d70c09154333e7b5a5a8c1c7805e43 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 21 Apr 2024 01:37:32 +0600 Subject: [PATCH 513/647] 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 514/647] 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 515/647] 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 516/647] 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 517/647] 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 518/647] 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 519/647] 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 520/647] 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 521/647] 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 522/647] 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 523/647] 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 524/647] 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 525/647] 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 526/647] 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 527/647] 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 528/647] 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 529/647] 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 530/647] 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 531/647] 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 532/647] 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 533/647] 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 534/647] 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 535/647] 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 536/647] 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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�(v<<^I*XN6!{Q2PwW+Nid^u`#PS3f0>HiUUnBg-0*v#`ztA%s@!fStTM~8te1EBf0@Db?eU+N40BpdYbnl}5;OozM zZP}-5e-j-K=K#W7h$bUNCCT%9N_xd>UZ8j8v$p$e-^QY7q53j-rBKPd-T*w|xm8cM z43h3mr)mW=H@aufYT9-w_Wx4EsjbeI(W^eumtoHqvZ&3xpNF#Nv`|VSfGz|8tFHVS zIgbpTrTxHy2EyEA`kwCD8i|gDsyWs%GZZ*b!Hj-{>cI3lJ|gbpPE`XpC$Z#^(D$=4 z_ZzDINcP}+I4zRq>GlCy7DN6nn-tF0_`vq!zw_j_JC zRf8K&;pjtmF2%SZkeYE{S;tN9*2VxNlA%LIOP?g``R=>nAU{NYkhz zmRskB*{%ky+T<75IS$w5&1{ez4P_^Rz@Y2dy4Bzc-5Sr1Tk}uNoEEKVd(fAOV+HI7 zq}3J2wo2|eT{{h%8Lh1s_8$Y`9$du}(@M&=_J0oRxW6d#0#L3jnD#qIHMj(LdsX)$ zDl=pmld_PI0`dEHVL3vX{^{1%Bjuz_ubVzgurs|xOgzK3%9%U4Aj1U>aq9~r6WC)( z>mDDyMD)jv>JS@rwy3*N{a%mZX_zea=KG8RMM3aXJkl;R{enO75<&053K5gDEF1PX zZ|VH2%h&SHSBs=wqx?jRuzY|EE#Fe~TUX8_@zVcy0`RSWD7}{YF%8#Qxpr|>8>~!c zuDdpc(^p7{ww$uAZb45Vu29DUz}-pIa(Q>ZKOKCFF`O~+o?k-~xF2X9InPM6B!V$NYS575%PRsbO4L8uoQ`Ox^lrC&sTj6F^me4UGw2;&$w@i8$Z6@ zdhRCM9wyYOlfassUTW#Vvyd1F#l-cZ=yLcjI+CjK$l33d^H*cU+faT&D26v^(%Q+h ztn47->(=^Sxt&Ld>MX;}VH7zH#a-~dltiCHzD0!Pg!-5?xry4^ECA`K=o2yjx&Xcq zw)yxT4k25Aej@?8_yOXTE_ky4gZ8B6Jey5_Njd{-g%`hOh+A@u6vh}Cv5`j}11roJ zc8hXY+1{U+vhD#rLeg(C@vgJ!=qTaQq9U|PrQNW}f#Os}H1+3Hcqnnn;up2IgEu{< zYwl&oxglP|nx*1`%?#?5pN3xf!qLnG)y_=2|6AFL)b9bXAu_eGsmYBt@Gb{Pe zzM_KLQf4E<94AZ>S!CsKggiWZsW6ccfd)CjS@h;C3*xJrt2?|cT?_V0j?_dfaP_k7 z3I$8I*QfTLV;Sd!sjej-U8^iT((7MD+yorg_Z8CFl{0q)2Zcsvdg{qi~{ z3hMaVD?ik2&n9&`c(k<)F-I@M$r6<8k3k1lKvIQb>WF2{egGm}X1fg`?iG<4vVY5vn5a!{;p&t+AlpXK%7{Yq^0dkYtqF z(Spnaz_hH5u6U>)44+1ALw8F%wUEAGp2lS z7Mi~jT$L(HYWRI%_e;pL8AX@eCK9MB*28Y?p}=O*miSfvVJ4K}_9wsXAQhIJiQ%*N zsv9GknX-aXd&Kiz45t8-&g^YFNo!6Kc4`SZg!LlhCyN>FwotM>1Y&)$TGSZ3uS`&I zbf%e^vB@o}Y$mL2J2i27`uKRRSN#~M&Ffla`(~_^s!@KO!lW!d=m$Wn)MG{nQ!4?1 zVV>=M32yn$7HHR%kLgQb-^ zwi;~t+=yZ&*B1l9?;$|bqb#=RjroBZCBfY!UrsVHm1Rvm|g;1EwuD{~Hw1S2y_Ak4`C_^LYvYkKS_pE?fX8YAly` zpcxln8V{uJvK z!0V%LH0)utO>+JAq0@jE;r;!p1Vm^PWnw!E*b2qq@rTi{`#uoO)t4V!%HJRBmqbj4 zY@1Z3`&}Xs@~tRED?j06V2#R}dLDwRnJa=qemo;_Vk8n&lhl#e2;#n|vG=TEBzW z8I#54*TAai#wGg6Lei)JC@pj{RV39`@?Idw>lfuOHGRYIvM3QnWH#eyY5Qy!QC?*% zjlwVQ=kM%B9=7so6$-KvCk0P9m00?OgLz$bDDz8nC&a#>@0_`!2Amj`QOS-Yswak`;A6#Ot7_y6rMCHgYIWGE6mNcJ=}JIF>W$Ao zs4s7}+DXn1_Y7Hp-VAV32mqJiw%x7>>YDJIq*Oc??+ZSVa=^m68$dyT7sH$2XPy5% z_+?CkZ;^<~C-Zv3@|X>Tv%;d6^3?iDa-xGw;;m-1vugC>8kq?Y-SCcTuU*|9*1YRh=ss zn{truw^PSYk5-4xw`zH{b>n`%6>nl&yqt{>w%;Ds9kEeBFuYb2fGDOf{kz=An3G8W zAks83EFcU_S#}dQrUdVA=MsjFCTKq=rqx}Ei5fFUIfVIr3?8u8fyWC`+bK!ZbtL!M zta5WQ05b>YiBv3oxJ*$7=Z_xvdTo-R2j1M+6YR3c*+SYSLY{g{frl;?uXQii~i+OMR4gJDeJ;c7AuCf>k zZXH98O^?2{nNF zbsEoOKMV{|&j(AO(7l`($ELnr`|wAaWoXkNX2@(X#Z%)PzRR2LuzanLOghU7sMjqqz6O*6Ztaaku5YCt^) z$GBTWDgr#+Gf0F7gMjUXfj4s_(eN?8I)G>8Ga|dg~kbugxvZ1tl$*Uw)h6@sw5hy${{H#??$vwkB+>_Bn!gq1M3SIAf*E z3z%c6>npa5y#TZ$H~xEol6&W?PmN1* zy!`m175>0shf6UkDGyR?iJ&a$1;g@>4T@gb=zcb)y6S+3Uq_itag z%Al``ctc=m_w#R>v`a^( zx!p4(CKW(fCKzUe`v;;GhZ(nD7N#1IY}>$gbhPeSSNb9wmZ7`c))$z!ouNO8EoMgQ@!q;qnA zFG=L)_BtKw(R?+Ll8+?h;4rHGJ^k3&OKp%FFB~i`yxlg~%LLXj1>POapVDs|7arjP#L)HS7)R3R<4hxWlS<^nq3XCLr0 zNCPzoL4S4joRmDboN|cT`6CShfV40G3?K8$KP;jQ4y1=X>@X5z=6z$NKSfh)EKt6@ zCR$w0X04b#U!#7+NVVf@qRbaP&CE})D2-ux!8%mN518wN6nLkyovHi zXV?}0Z^Wkh#dWMvC%FpbXj{uph?n5Gt&;xEb(lwQ}s{a84ay&Ke95T!7-}j3< z4&8bRL@3h*bH2G-X&M)n1O7XHJlhyXM6fC$S`R$Ff8>{^T=zLN`dk?)vjHp}bpcSn zDruQEEue4kkBe1?jKk&c{k~NP=EUH`JI{i2)xntBd{!v@pxc6>-gIKyJKC>5wr>P6 zSPD&0>d)ExMiv<@_9}b)>5un|siX9#pZ|RKev?)exOs!jF-0r`EUCp1^5!b5TK>1BA-Uu zFv#$VKTOy>DKP*aO$cf_8_!<+C%=dm{W}l^0R>iVx8?8(3r*4iJcaA-FZIQl&HUp( zuw(XuGs{a->&+1_KMrKYU0wL`7dQ8xz3X-S$!RgwU*T1H`g}ha-E`d(5)>UB7md?J z+^EB-e~mqPmz6%@VGcf4 z{tz#VAX8inK|fe3+wg!+8oG;E`wsVM8e`M}kVSV^(KuX#U~f|YUGGW_bfpzN`+pX4 zA4FiTX;l@3#qPx zJR8|a3_nJ8+t6@2s$!)2h71f#0ZWrRu0x8*h&GDJVN3)6$g!qz#b5>s@fXJ<<7gwR zO8FY^T(S6|l(Zm@FLKs>rm>)l&4kns2BcAt2ho8YOJYPnS}5B+#^Ps$4A34u*!Jt{ zX^7f+8#3nbi-kiBD;2r*`;FVure?$GJN2{+FDqz~39v@u0Sf%g2;zL&^tIex89vj# zmmQN=llIPXDKr{hP!JapZt52BZE}ZE&uo6i2;b0XU`QjjH{3FvI%d2&r*l=v_`TA) z`nZ(q2W33e79EfJ?`+v0sNwT)xqlEM1}YKjUn`JqM98qiDU(UmW2I9Q0Nm8EzMjtS zdb2-VGKbEM%2xsq$S|&NVo8vKQ65*8OrqGeAmR7eU-{&#ou3JlTCOpT4N~jsf1H>% zi812pdp;Vn`}CtS#rev6mKf>3-SEc`|I!^grITca*LY$*(vZ!Lqst9O9x0@JYYwp_ z&k1=Jj#aud+0dIXDDJ4@s(WSZo|oVXm1b^jjA=7(F)s9MfitH^E$kRj7E&cH9$bsm zEpm9OJELb`!&!1?t(*Rt2T+KD@m={5Disb2;7}|kJ;FriTwR|K-=j^YBxXRB4LEHv z_tsimGOn)p>#N_5>!V5;I!}rQtY_S^S|&Xzo)78Ofek&xij=8_mrd!|(~Innw-%Gi zS1#VCudW#nqr{=MsK_TT;;DA4q9ebTNESM3VXU|QkBGqU`_lT~hdD`Mn4uRpiH^T%C^RoJ@rb$s&ODjp*g}<2Q2EXnI8$A`St+ zMJqFIAXK1%?I22LnyBF^&(pn%lFXxN5haz;sO+_u`jN21 z*ON;|&&A_fX?@vqG@d;RRjWHwk5*v{6RE`4=Mt_PKSv7od2c2MLjScAoXmU2h)G@kmKq^#~=S7uSJjf;X7sW znVe)JAxzn7An1QL;Ys+0(bIDI);E#mllN7JR05eQve7H2XT=<7E!`{r5$5biuPgz zS~y`7gH?QXx;4ldl&Qpq<_4&D6M(>?Q0%iwXu&@BF%;8Hd$f=^gOc&SjNIk*QV@}) zb}#Dr*jbuh-@HNPy7NOxYzNe5-}7Rtz}NjlkXU^UHIzOQtSw>x7an3r08fx)*SH}A zkx5Db0e6*_KV7ka(wp;${w-8Zq4_<+4;mlSXmC*R*qQcOeZ@nyETdI$=q+oKlVU93 zIXfavt}gX>A5R$=fzvsrKc62rIraL2Unr*lIjZqpaKBy)qH*M-&g^m%4Ys_f1EQhH zluG)O{&W50stK>H(HrBV+VSxBQ*zSaskxu0BY)GBvvmuESTlXNTa#IJ3xq_~J;&(A z)H9+EALn&B@QI92haQDFE=vPdjbRsuWncu##X_18>p4am`wVd2?PHQa!9?#@=Xk!^ z13UT)5Srtnv6`WMwgRC&W5^8?t4>}YK)F)(waE0j$>%#(x=CaYnR`z zxv8SM-XBQzdABZamdD?HdH)MnZvgz;T;b0gYfO`kR*Wr}h8gXUi9c^D=>oO6>~zU- zvLVS{i&CUsfJq0j8LO$GEM*D+qb$LyaW8$vk;9O*JH#6Gh#5e6fgF!#jSWD=q!+kB zp$kHydBFz*N7NWQ(L%V=Cy%i3CE70}kOmz?4%-wvjT5wanO7&-vdCrVP=bVVHA-xw z1R5J(>C}dSf(hKD*J(PdGGpnP<@vbiNW7;)0w{TO2?0YIqtir0OA3b8p;7L|Th{U< z4A+6yeeVBKmOYk?Wed&dV0uN%Fv#d&*!yb?mDfK|a_VHd)vah{*;oFIJBSN_b&-}}>QK)< z6>Cxw*(NU4`tw(f4ug4MdhF+9J?f}TEI8Tt3K5y*eDRAM^ds&VV|pb$v&j)&pB!zI zkpQRRw&`HX`C~UGUgBfv)qjiq5P&ZS4ObjX1?!E+&8;Q8W_;;~d(~amJ~r-(<{!Q? za(U1Brd0*RoK^HA4EXn(7?v;~U_^w7tNG2(6cp2f0Hp9*fSg;TzBjQ<9nMlQf1MbA zIGHLZu@az87G;3a%_vZTCyxO~*OhqSlbe2Aov<(lq90YYXCCQZL#TPe43GCYNygZe zJ)xG*`Vdls@3oATpBi?!O0?yW=BO=3B#S_(?|4~4mH1GNyZ5!7@C?K{%FUp2;q>6b~|1j&wvCFt{;YU^;FhmE&OaUBVLW*fZe~v$&fuP_JziZ}_xO~q) zWBeg?7lKKOBgCiaE|vOy!v=I;rgbzr%##-h)sLqtO`M`k;p6y}hLaUWX4kh<7Onah z^9c!1vGEGwS7-mIILS@t{TF&JpncdviT}XFzj&bL0(3m(uq|W=x?;w7G#mbey16+f z-~M?_eOwZ`n~#NC=C9aqYa-9CSfd*}cdAm>D2rz2C^t`vUQe^j(AggkYZ;SK@5Ka= z4MOUGPEMC}y?Ra&kPSk&V=8cO2?*eC*9!)M*)s8QfjTnnf!4#iSO~Iyc~-2zfW6BG zN?CX2cAA@iF+oXx`qYzc`3ZlAGr=@2d6KjYRaa@6$#t7eB(hQtntwHR#-t$0D;04= zJ3jzM{XJgs0$sR@i60vE1fS7sQSg4Ua|;`-wTuC&m#@Q$Qn>|L zy(~xns3!a#Ysu-bq;&jmH@y1cBj-ciAJBhQ@mN~75Q|_qzNJU%Ua<8)-rQi%95tog|yMBC;Rop}Psl1=DI7zkL)}r!jc1E(i|c}kicjRxDBj*njf^^f`etxgw@u@ z=}{D@lO?)+iCce(E@db#Pmcf1s*$xR)=@We*Aa4g@DXxq?snbWuB;I;H3KA7kFBGFe~KQ(svZ;!I`q^!QJ_G6#QVdUGeN{G5yMTq;1AFbEV=9FbcGR?F9_iZjR5tk5j}WQpr9mv zZNibmO6gQhG31v6b`tKqZoMDB)1O=)qD>+K`RX}W zfKY(LpT~-i1^-vTJMqKYD-^qgV%b{jOPdE{lX0=QjFYT;U(hqxohN5U+!nrkRlABj z7RNdK_)-<(?qXMwo%$ohlS}8t{T6{Q6eW{5JfIQAaEyFm#qnasb zppmEs4W!3I1ZM#!sltgw)3Uoqm6UQiDQ{v=jdqTR)R{Zr70jqGPjO&)xaeN|xByRG z8t%3`*u?yPbw1k8HGG%H8re2L38TRqwA!9q2`rYhkrfYzQQhz$4_Rbqu?@^Gu*QmG z=;Tvpno2WhRC{*S-@Crr{AloVa&4=yxXYxK{q1UzQdj6rpF!H~kqO(>`D{FndviV$ zA+p;wGE_Y90Ii@wT3e!VO^Fu(PfSx2uRm$-3>oKhoCpPhOqoZBKbtv1z-VT>2z2Dx zCZVG^k%GvOmT$PyV?p;S`DT_#W7nyptf`R|G!K$B5?)2?mcmy34!;hT3b_RP#y~ac zfNR=o@rKUo%K!fcz!%FEtuER$J>#(~A1UrClZ)MT#4fpN`ib@z$5|VYJ+o;PPFm&G zTC40kxfVJ2`$;S1s(HWk_|SChi}lRdNr~;k0{@xoMgQ`N!(Ul;Vcwpr_xt6urdO@h z6}AeN)hv&>y-0ayRK5atp+v?sE%dn^#*);xF*z{~g1a?FcKhvH` zH$hws!ln>Y4v+wyIc0r~KY}_rp^1Mvc9=PJJdR3l!Nq}zaXW($Ar%%PSM~8W#3|yA z&6N=2fs}?6rH^yOul9+{Cx}Cv;kzv=tyKT=<{T31@KlJE#>w5;MNuOk7*t=#+=$k(@9rO^qK-ivonqT(m>Fx`WDpQ&>$k73I(_p zAj>@{;(_`Dmb>hHjml*UA8BE)cdvQ$bl8eBMHnZtJf7LSBO~_LR-hi9r;^FKq46$< zl$|{_DjDZ|w~rY&Rd_oVBT1|iC(;p5Ew_s$hgnVK{(V+>cQLrv!Qx08t!5Nk<&uGh zN(#u^-pnAjT9N1AoG4O1BG0X0`tJdUpDn5xfAU;`N>?cP`oHFcF$_N?VlM#M0TWZy zGD^-^Wp~^(z@MfMUOFBX!0PWI8C2=Q6Fj+f;G1!UpR4;6oGrDBti&znk{4B&G(UFg z8olS_{QR=i-sbI9Qn4Dac+d-QSwKpvR=QVNDAEw{3s;v6)jvWy$V>e`55uy)>qG?_ z&u0veApEaKyy!>!n6C8P9S0W+wrp&UgVAY6 zC%E;`HtkIg(l=%`W^cBqoH*3~Ew5scvNst15I{bBOrFH`(gv|k0*pfK+e$tXs4nP*U-RG`;y9lqe##n2~($RL-y-Dj<|@s_b+%rmTsSp z?CO2KPjB%@DwV~0QuzaQujo3`n~`PHICE_}?6!r*ID(pKTdkUTD?OfUR)`~1by%%`BYebTapAL>T5|H&|S@V1eH~+NwPm!>m zeSh4E&4xiErdTP<#YKN}hzYQyu#)u|KWXRJqro04_~^Mt-`2sa zBPF9f89v&=JLLZQ_62~#aKCJ;iTwV6O)X_8%z6L-ON6GM0n$Dw&frosk`<+K_F7t1 zn8M4`$Y)~D2{0^$!x3d<3M|zT@cwX*UyU@4zruGjKsM#bg7Xvl^yrNPS>QrNPPR}3 zN#Qkw*PH1H@hngpx52WfX=0)|R^E7KI?`lv%$k&QF zr3|OON-R;F)qpzLH5L>8#bllE;;{5erO_5(B`6^u7a<-{X=*Mv46i^(MQ7NL^NH=& zy2=h4Ir{y-Y1uUZxm2do#oj(Okn0Re8mY1XfHZ?8SZ4ch+3ZXaREdQoS!M%BNeOxS z;2MAwhH9IHK=>m?mnFXn4nq54o)be^t74iJ`Jom`e8G&gj=98H?6&8Z`^qrcQHE6M znOv|}I}1m-j++%Naqr#nnmAnOk+POJP0j%xYx|1 zQjdj3X2xJXq=27IN?r=y=0ods!Wb_#?pF`q$ElP*0&?vC2BxGGNS9$H0~$1*zXtiP zV|(PG?5w#y7E=|3W^`sSR&v14@&h(;Xi3o^z)>dg+fq}(8p$fpjhc1p-}S$44w{`h z)&FjUXd@`3;Yh~SiHKJUl^<|UL@M1qdWPA-!i=n^Gg2WSovv3!($#qg7Ij##V>Q{h zeGa%6fSaxb&8*s z2S*weJljbAJD2{2)*nK}rl1Zt6Wms=Sv1{NggdBK>RBPedtvdXSk#yTdQu*TROePf z<1|88!8GBqzIujAV|SZ_5mU-qe&{EMJCcPeRKASajL2vf#-p zf1swUR3`J03s~CWpX_JKrLov#s5KW->4A$1J7K0Xk$`l>h!cjBXq%GNhky;ZqG-r@ zUw0Fyt&Zx}2gAVSPVU5l29nO7VO4snf$75YJH*YX+=louVy% zGF(3uf&TKn7C4^OzFr{ldr*mEpGE4UB&KCW7eWQk=GAHPG)R6 z^sll)H#h!g0SC1cf;v`KLl=9I`}i@ncx$4kw2OoYtiti?qVN2)gz9ykBuK@)u+A+oZ`Cj-;={Lj)@Tgj?aSiC;xb95dR6 zn@k$O#%aW=z`igsA})&E0V!=$$-2rIjcl51H~axJ@dVVW*-CaSPMT@LyJ8{b(W7Q#FyR@gE8&Yq+BJ)q%Q_4IU|iz!Zfon)00$X zUd&Rlgtlp(m?jjry}K=H@o>TnE+;>Pq8R{i?fkFdvT6Pobj9t5#5w_iN1cf*x5yEDaQ*=k$JPdlS+~B&Wc2*6rn*U~HYa7L!{3-!#`zGJw`2=j?Wz_pE!AIm# z<}&*u2$C!&VkI;fKoEy>Y`%RhV_02dla9>$*C+$X34p9GT`t@4&^SfR4{A8nei7tS=X^$!9QR zuZ$W;GG<8u=wV)%Ll$I-9r#TA!qZ1g!WKkgfdzqFsBjd1*j>Y>i5QVVVH8IJ9I#?& z5e{<0TIAn1aN&^zG0;22TDQdgjfsaAs=0cB;`)8+qi6$mVwmbU2?0o?sh)xx3ZuMj39Xj+C%mZ9-9doT*lkfjLKKJeN`0qdq8E$p@*0ytW zGs2{Y#@YVgUoRtQKfV4vZQFKSJ=y~RNenXuTH{46ZdIZZg`PSi8~_d(R1 z?(c4*`g6;P!V@B3$K#f=K< zvz9B1gh}C9GhuE1A9=rFxW)vmAjOZvko_MGS-EtlwBzxmtsPhtiD z3?sr1+`pach-kez7wUg9$T5mpWVqQYgQe(+|-0V(7XqU%`nIwX~4oLb1Yn zV~Z8U;bT^Q)LE=9+Voe`aspj@WG7SqXEfLS7uUml02*#uMe~CM!oYEEKu?jO##`Z+6wEIj`-%UywDD zVxG{{F!tZK_nsgAW8tUnRzIp09!n?{=t7G-sGD!Z4Y573*n$?YYW-2jyn&W17ml4w z;aXCTPT&jAM+@QUZPGx?55+xeh+d&7a@^U1mF}Gx&3}ITO3hdnph!`jXQ8D_2QZ=( z{DPVK;WXaBsBc(Enjx6c-BEc;ahpeQlUa=rsf7NCD~)t^*9;7&^miT(CR$t^0bbFE zkroJ5q4(Yz7p@M@`{3SZuXgB6=R`&h2WOqNBjJ2%j| z2ANh&RpsZ#kcr(#UDLp*B;{H9{gCaFuw7G`O-ThOiH#W7>1e)_jdwagM%%nc(*D}X zE-UBotgQ1y%ay=3)hR%lLz;zCM80n@$#n~l=l*Xe`XyFLE7Rf|rCc`j-B$t-z<5Vw zs3YZ0c75d^MeASXP?6lhtq0gGh}EfpCJU%QVLV6)CcQ)>CN4FPYMWa2Wg@Bsc?Y{* zpKahq)bzH>J$^l4u|{}5;X8f!P{Xg4ogngAkkV1pbY|w~f~Sodhn|iGWiFF0aDI|5 ztts8piyrR3xOfwQe+f-O&?5K}5B=jXaaA17IED(PtxL|2KkU z{yyj1FKGJzJhMcI70fo9QpZiD^P?gauSk$vtV>O?v54k^P#e^cp|>M33%~>X4d%^* zkt-}6_JAS239^`@thWu4Y$OT=_!m%5^c!eBa1fsgS#545^mrN_x8AmV`pErR3V92! znDPHeItzw2w`L0`xDz}`i#rr|cXziIm*8%txVt;W-QC^Y9f~_`u~MMG&G~MA!k#_* zoy^R7)>xyKMUTd%a*@3+e>kj<`53pkgU2$Y5R<-*tO=I5L! zB$C0ny{p(RmumNK0<_5$hA_2ce7`gTS?XExPyG3>_eO4Ii)K>I%wnlaG}kJ z75y5%xI5Q9^#7eG0;BIjP+DW*e6v->D3RM0w*iTmdm-P3O;PY@^USn^Nw*e}6CX-+ zu`MO4_i9dY%}$nrSFgd$t;|Y~5x2jQVS|PM|@~6mC3l{pWm%@=Y3Xl zQwfQO(6c`Zh&TRt;F!R~&i=$({A}?emkPAB)djE9nX@vXnS#W9Vu6AEK;xkIh}td` zBQl$7@+eL{I8(_=w;4(RiSfs*p2LI2%{9tPCCjYJ6`c0-2d7b04+J8`WE=To;faEe znsA}5Or)f0ixb?~RiBplp;WJybd#mV+tJP`(5{}&%LAj2IE0Y%BWd9~KE%Q7b##0v zTSSzuXK1-Q-67k)`OZDwDsqg&=91Xtt;NPhicB5=vLVCV!yY$o=m`611w)b@pl@?$ zQ<%RW>}0LlZ){RH<$;e^kmP~`t5fwnzgTMjRvP{rf))Dj_f)~jL(sLOw2fevJDt^t z7kN*Hy8sF#L42jPL{Gw5TeolCU#EheYWS}Q7uK{?BCfe4A8Dpvb@fv0gXd*?V)^g4 zlU!n`+4g_ga36p#mnl@sx<)bG^k0Bl=)cAP`p5n9mRH7_d0evhXZ?C_gWYI4!@cxZ zABPo%-Xd;=mua_B`bpAkgf%)VKr|5W1(3Cbf+fRh$w!l6FpUofc7I@GOx0pA}7 z@3xFZNiBz$T)Xpeb7$&dH-YbX1S|r~!g2S}!jPKY-YMt9^Q4a^gn#Xq`GnhUqP4U~ zr_A_JuFUnDsORiOybyF|skeEwP1-BItyrdk|N8X_noRmH#}t3IIdoJ2pk0ZgHgIgy zDO&3pzZO-|viHOCHHaZeEEGlrz>fi^k=Wvcg2V@yz3Fn)PnuW0Zm+>(V|yqo=Hi4) zs5zN038_|Q`PmYbn0I~KTBQ;g-YC#sc5CYOdB;ROIeA`|S6?v{5kzy9eRZ;vFi4(( z9GA`FcK>(S*HCFlJd`)R2AOH5h4QAayl(-ti07J8)b&i*N{l?KTAng)y8DR&DDI>WKC$Ua;4P><71T@Kw>Vv zitK|`sJ=`tVPnkPm+~J|_Gx*VmJ&VixpbK|7DQ?{)oRPWv(+73U(hsgt+jh7@<7x( z{AOX?o^5WOvT9lYgdH*wV@$=@%t=)fSYX7*fQ7(99TS*4l)zD-6fApy0RvW$I=MkA z3VkUDo^9;mJNx2!W-jBWaO}uj&QNYg+WKi%^Jd@G(O;?A_0>6E8)saFYvA{0+uM!g zret5a|DK*x00A3R^whm@G1+AGFqS3sH)CmP4n>t;hji}Z*B9ZP;w=qf_SF1)Rkpl7 zS3JIKLXL0lO`o`TcV2{Ft`-vBe%Xcm39An49P}BUz>s9Fu5QkyS(A7w{?t2?WwQrJ zk%TXXd5HvCrb`if;oH>n>vP+P{R? z1nMZ@ewU>NxT@BAP=mj-&W=#{eV*-7VKHswE+yXOpr7rEljxB@rP5y74^<;#ekC0n z#`jSp$>)o=P#{MAOBYjL$v!^2x41_zz@Qxio6D@~jD+IA|g35R}Ev&3H31rd`>3jt6aIt+y*^6LnoOp$;n( z-afKtG@;)#g=Q1%wr3*sR8kjRHGjOcVa}3Z%2RFAWcxgQc5s70XuLAj~Wf0 z4Ro-CfDSe$;zb5ZCBPanoU?gI8Z$N=sA*q?mW7be1$9GJ^riJQpN(TaH!wdwKE!Bu zsBkAxRbM>TdMpe1{&2YSj}fcc*kaI-8Rou{Ll&$p&Pe*JRgSrqn0;JjHb-e|x@A;@ z-RE5SisRF9uYZ`t2RzzP68`ez4)=Rn{6DMDm6*)+^X#|q3n2>B=J4ts2B-c#WDQCo zl^`5lPXMfa`s+Nd4GnA;8Y7W7fjpI>IbF;;T|*{*e850+xpSh($k0*arKk;Lw0o6? z5s@~gCZxxOBva^{IR4@^kl3wGclqhDGjr;IYKGc9SA+GuL|{ye?( zt!3IGxF}h}eBPi+K&a1N?{l>Kn`y$3=gRl?22*obcxnqZ66TaDC_3=b@>>5SYsx^k zm={+q3rhR#FnUYPUX#v%KVnvoBmCW-Kq9jNJRP#5tzu%1X( z91pa}GI4+}tHsK;*H$Q})gr`JhvU*RW>n_TA8%uo`^v0j%M+d>(pR>Owt;Yd)2@tr zrBvbSRKk2WhfPhmNJTu`md+pN^S<-?6c_EdgY*w;jW9YXTKijasaga(@t%~+UKyKXol)e`LlkH8AggqJo1JqcE9fGX} z%m~lfcIf$*_e%3S!In@XEd8a} zGfKN~*lo z%q?_E@!y&;L1s3TPnU5q^oc>JtW=1|@&yIIJ||%PC%)sa_tHA-r_nv>Ww#U=q-xg_ zfivbxZb@mqWrr%Erkwi!t=YtEy23= z?@yNzSPKHi0M(R5hsUFSxx)7w8MJT-IXlY*8&R&OC}XibM)49FN;P;y1oBRTvZ2m# z1TncT48^+{zOCv82_je%m%Hmr*TjvD^%dRSE-30|2y0iyWaD%rrvWA2z@^5KP%0xN zjYoQs5bl1M4?|S;1t62>62;CXjPV!ItWqgk~TPK&t@}Tel{{)9<>unEax;3>F$CNl&xG8 z9ZiXqRj2g-$g5Mwfhj|)|0YClrcqFeEHfP7v(JHq5myMJds6M@vO+{BTMTNhLZgelU>Pg>W#RHZ>p)CO9mB3CjvjRNYAn z$CW!?2`l&@VFwe(Zub4;50&fsqneDl%yZoDHGN!gPsaHfqN???YN_`#6_tWaT zU!r++2xKwb63>O6(LIffV2XIwh5jL{N<&;p`6oivM zxBOp#)&aQZ-X>Qi>4%;yXUx?!dq=~O%p6wa04x}MyCLQN28xJLVQa8pCo$wY9(Q35 zmsrxT&az!y#KFPqy7^t0IN>41mwb8IqdYn&*Jfrs4|}LM7tc(Q3UGtrTusk#ixP(M zAZpAR&zYjdaIZC$d(hZ!rsijR^N{=R^*!cf;W6gatE&6NR{!lenc#bW8mFLoT-HWj z&ULH`9@4kW{icd+;zhd>g_4DX+us>&83fCapQ3;v2gZm;A#6nA=e}D}gtPerfL7xY zp#2~mN!lzPzj&DCBNGxLrBSfh{7O8*`IfgvX&Tk`9kD1ae^H8FjB zK})UJx7q_YtA~H{60N>))M9X7*mruL@7bbi86xF=9ZEtq`5ZC99P<+u&Tj5Q2p}`S z*m^`IW=ILup2=2%Fwmuc^1{T;+!{#`vUbkJd+dM7^4#^YcLCTT2bWHPeGB=bDTe52>D4 zx^M%Z(H!_J!V*#Hsr^w)h=X4~OEfJGN@06PP{6*4r>%e|?>Y_@{V#im^CL~tw zeggORNn^l-shVW{1qVUh={I%>7?9_0i*z%?7W@WJ7j(dJZy<60OsGT&Ap3Pw7 zP^S3hJz5k0<{ImGiFKniklt2BuKtqEayUouV&?Jp2h>*?kq2r5&b2pUAM0jo(k-wO zHJoEkUCJr<-Be+%=+1SG9HXhxlm7;xqt8yC0U0jd%YT3h{Ju zN~rG{MGyp&P@=K1nyO*}#DA*7y;<2}RHHW~=wZ#{V6w3}C(x0H!=j}Isw*MG9T}k& ztFFK+)H1;{ST~gaJBqF9ushMhsxdvPL{FLK|FqQFx@~#2^uvZ@baGGnnb=D8!wK#U z_jphZW~Ihh|E2-*mBG9k-l9+mESs{HGoAByk6@-~- z-@-KX!Ga^~lVZygWO;g1!m~1q{a^pu9`B)|zJ1b51Gcnum)f{u(k57u(CLfmbgDY# zKf$3T!ZQ<;H?T)jyg_@QGwbu3kTTv+|Cjfb!+u+I%$q$Kd)y7rlY}Wzx3>`p^hs^psqo)t$VSJjj~vYqm+&;kkVA%E7{; z&Zo*PQv2JV%`28ZuEMXGaI<8_%6qXIY(kmW`Ihweok03-K@mpCh& zs*OVEzf|1`AVIbji8bL8-)@5Vg*Vnrf&%ehobg;TS}8T>&4514GP^R*ef|tfcg(AL zKn?ZP!napL*ECME@^^PTqRupf_O6%Z3ir^z%9`MWkg|m|g&H;H51T`4$jFiv)32pg zkFW2eqxMh|sAH4ax9(1uL~{?nJf$MYn0-1Pt^^=)GiVI zR9P~R4%DigS>Z+TFvd#xH&DE#ANd5Sej(?U4V4T9%nQ$|Yl#-HToEFwbeZrvnacw$ z@zQ9&uVPxx;#G?-JdvH#Pszl#A8U!7$H)CJqF$ELy&Bw9_#|Y}Ly$ZlLWXS@`!D2n zGftpvZKKAG0s|#r@5h%Nkhk@H!dqHI1ozLqqjYr{q$s8?;psSSrv?4J< zq!R9b0a^>d6Z@`oRliwS_37+2jpF!EBr^_Ni2`iCF>izydKdzFz1D~Brau#kgwu;% z^c>%J{OMk$Dn<_tRCCfHdYtk!hiEA4+Uge+J{wepiMC(2*hm*p7b!?( z%%u7_s28AQT^5+8)Dcnv*r$+uPCd7==~ks#&toPEaYAGi1JgcJ1=0c(medW6ia9Oi zt0!<gYODq(eZ#ki#1^WgATz2qDhUOV7yzuKZHL^v-}a*YZaOnvynu!gD` zaBU>84)y!SiyMn_zly2LXCJop&1Q7(%F4hPrM!b~F!ViLa)^vsu61qyVxzeOw|$>U zb~U`FZcZD`&%rM06xmM7d^(;PC^xC&|9fkQ0Cu932OwIR%dvmIGLA*h{?<(mJsS%C>3w{!H- zz*wS)!YfJe1BJ{8`^4009As5%Wx5U5`icrZ#GE$B$rg<{uU1c{_fI{zU<6ofM6F$i z5yX@IUu}K|AP_2o($`ri8rjad%Cdy!W-Mh+?ZbZ%bU4^8Wjy%GiL50eZdx8$;OKEZ zmgk%_IIlf1voJXYl8H1@@m6i6G%O(xqTbH^}0 z?RZUK2D{*(-Dir@8H%!ZghTi?QXve;p$Y6Jf$` zO{CZ<0)z|qeT%Y~&dTe_bhnPmdebH;*I_F{ODV%8XH{tcE;no9M$c(FGamNt}-fl zDTPAV|Fc2CJN|Eqzeds6bmm^1ZFHOMc&g{_lShnlqo+IuvVOU3eBWk49ar1jfEvRk zH&3r*dR9)%tb}hSwY7I9?*44W3!tTngm+i*Rb)(l6GgJSHsDB%mCpy6F@ZF771-J;cS%TKmI@FgB1GuTM6=+6#k5sbKP%f`ht3_N&-0HLhy>1rvS&ZE2 z|6%o5WeF%>tbbu-Vr0c<78hXS6lutvF7h=pp^Kp-`Rvtx8~ylm`hNC0vP9EX&*KxO zL#(GTt_Vr6Y;!runZZ_!gd#fc!I|cPp%nIDjV31Rolk`IY@Vr2-T_MmF)b9@#%ccH zAbZkekUoy;BpEJ6X<#~O16I~XmWc@)fri{gbw(I2XgW87p{WLQ-6ra1QwvE^OSDlp zpud?{EU+K<42C)AAcZU_5q)}Lb>iEBZ1RE}(UG~6d#@UfbFsxr#(Knfxj0g!@m){? zb@P8u4|K3RQzTYXzh=4wop6;>d_~eRrIjT>hd-I1m|1mj3?|glpU(7OQftDau?e?L zlWeEkPJ2Av-AmkbFE;B)%OB`!K)hX42ll-1;3@WL~6tX{;bio`g zx+uPc!wyo+fyieN^rs;E0>y}uFe)OP7`P(|jcYy;`Co8#D0ANEd+s2TTB+-eXQXu2 z>JXT39Mqfe0vSI-6p@1=?1YI!aO{yps|h$wvgLG++M=5&*&qU@axoGRGw5i^f^=8p zz3=_a*5vQ%wR?8$ngN;+H@$b(oFk87l#318B;#qR*p%R+kI9_N4&^4A?WB@WdZ(=$ zR;nuSyPXZ+KY#gHX%&#=Fai<^-~1CsDa3j+Wauosqh3g54}lO(B^^;3y! zz4BKmHu~@hIjUAKKizb>aX9+hfr)(}@1DV|8}^V(P5(VP?1&xTR7NX4`^WFfsEVKlN+6(QWT5M zMXF0j_oB^9*yrbM`k50G&y6%NS*r5p5zcyrOiOE`Vw`*V<;$~4sZn^Ya1yJ3>8=eY zhuZ_~_>H4H>n#*UP;r8R7VwhlDUGD3JwI-uJ-SDGG^DUxvbm=wb#}8(Ea3DZ1sH+J zMJQ%6*0&LyVcCKx^^JDHg-PF1;z(zh@9$VIuz>V6=6!`8{KjD7ic@>~(E!tNq=lpq z3_}Z4&Ux8@gYg&4q9{(JDnZq!_5fB4K) z4yCoyV7@~dA<!THfeII}<*!druug2=Mpf6ydOJR8MAEYEFE8EM1y*g)hHA z{yXd^0GKab0&0vGsl8AZhh(_PKfk~M6 zVnJ2|%g4FgJR`jWpyI4@IY1d@?)f)Po3r$dV$@3S==ZQb01&FlDezDIG9)q^7l9o3 zz0^S_Lu`~R5CAexl&qxCS2MX1>^r}TMz`;DKC!ji-`4}H`oV>*BJ5LuSp{gB^{G46 zg=h{H+gr7Wq`(n%w7?~yQCy?T0`a-ms$RGM`Es`tTHlix-Ba})cm^`WVgp43NF zT*dR~MWC_*ij?F$k#6MlqLu94--MK=&-+e!Wf8#69R|PbO=BQoS$-xPa*%YkE?-Ai zMsNf&s}}$cltGz~PA$5S!Ab|>*K6bZD?YY^W-iqbNj8RC>_Rpwu~j+2-~KDggM+7$ z@*}@lGr|TU6}z1r-powPBn5$6R-@L^$T9&19#)iIq4sy;5+6leGNl3-AQ7vQ6yGq1 zc}5^|b3xa!ug3PA$gRdqQfHfjt$(V_n1|O``-f2X!WY^PU{#MQ5Y@xKu?Q4N;%U8AtJz-If$loKvYZ@t-4q$ zm%;oiqm2%LuLq!9d;BCrWOc7c5)1i8(tZ=6j#EP~M~a{%)to)Ej~bmt zNte8-p=MIO3vI{EeSM%3dynaR!I^KGN=C#imY#0lY zi;548FxZALVk!L^G-9ju7)AH>it%~#2RpoZs%0ySj@ajUj1*_>1UO;vw)RtA|9yy| zB_{cIxta#fDmhLYu5Q8mYBjPxW1+}M7M3z`dIfZ(+aWXmi^tE!6(g-Mkyr4prluYw ztp&{rBq=;*Ms=xF>zREl23i71n$m-m)aW(5$BfvFDXwjNUwXF7M&_f&rgC)~NEWg4 z&~bu~VFoiRvjYUN+L{&tFr_Ad6`j5f`wV2L)P_{F_5^pn^{<_G$q*G48WR~#%&$3y zaZ^UWI#FY?n!OMv;k3BU#mW&FEO^A^09#jq` zvat#>D(=Xss?4-SXNSyxmPkv&FhH$9CV;4JSUw1*gHAsX8W463@hV#&iVbj0+@yZ; z-l%#lZ>#1o*<0=@Kfn(Y}Ae8~8)bg`9RMNCKWDnS6=a1c;|XG6z$ z5UFuM&Fj~QB1w#Xrc#V3KAJfV5{fC*LY$a~x;CwL<=Eac#K96NgXV#lf@nz&NQinW z(p__#SH$75r$Lk*DDo|~iPxpq@O1y*PRutIP#~-X?`)34XAxQGR@i?5 z0%Q5BT=#HPZm>Z7%1Vo~B5BmBu`+$vNSlD<|USUPIMfO zPu5C&(ra)`VhVOFGIv|f|6ET$Wvl-h&fmtTPEy7bjQDuDTR-3q0Km*30jMfG&%4P8 z@fBGcl24IPGctj={q=Z_#_oUdV8urpH{i%E;M{i=NgnRA&tuGu{-C1Fz4EVPi*|mf zAvI^9WWjU25qXDhjy(+D-Z%|`)bO=F$79ZN8d8Ek!0kmCAB32~nTX*Mbui7hmgJ!a z=!)Zmq$6ZIdSiYlm3}p`ht{l~q5zP`ZrVW7(0q)Vpb>IH=7d8aGG0b7mE6(;q$5VH zshG+>b$Ia)k(#kHD}}2fa8W!{pA0hq91RodfGbylK!wmYrf|%dIo*+(oPhQACBhVu zxQ4}U==XJ3tzt%9n{7jzq_(mi$y8W>h<$Q-&tD*x@2TgpPBsf^Z{PdB&QNFu{Z}aw zSh%WO@5de-v7f&}ZE^)f#u@Erh%elQrqFPcVBpD6O9Kgq6O&nE#mi63$c*IlOh+d2 zY|=I_4{Z&FKJC`eh9YPp0haiUfe2sL>R3?@!6{?~34i3RQ4WYe8EC3_Fp{OxRMe4U zfdIX)dc`lU>52qTISGWm*qfP+yc`iPn9ExnAq^B__R5x(oC>9LjO!=;2Em1(v);nIF z2gpq}4lL4YC#6~U@(@=@oB2i+np|}r{%Ek-TQInt3;STE(Pgv62h)wvEN~Sp@onW{`pyj`C+_rE{#cQbPc7w#87#>o6H)`#ej^I%uRD0|N$OvX#3s?~)~He}z7PK+x7?P-fbBy9i7hF<^z zqf{scgp1*CgUxGM<4UEF>~1KQj$g>(@W_gT_pSd6lqwJXoz{IBl=Ys>s+#0m=8TDD z1z1II*A(6tsQ#_K3Hihy%4Oh&6m>mNsxaIE8mW%WEDE1C1%DXrvzy3B%~)$~RSs9I)SdPM~>KoF+Qo4z)FQU8cy|8c%u1 z6YoZ?(Qiy4|9aHom54j`xHhPH7eA&$`ZAoMG=g~38+(%lNE6A%upklPu==z}cT0C9 ztVoH~3sV3cIcgXTqbt~1zQ1a4M*5Cf1w1b_5&hm@-A$kyV@Pbl;{3uTh?Gbh_6O!% zz1j#5E2$30PY*8_(=<)@r%U_53JXn}EM9F<80@MT0M?ESga}sEjh?6+6(Ae#!q&A3 zgp5vMVFVykFDS|&Z&@oyYcYEhH%=f;)F0@{5$t;J7O>Dk>>~%Q@E)7?`2-}GQk^=_ zz3Ixoc1Y;2nfxoo3FrsiO`j4UY*ra1*yUXud3`TKzaJRhRMsV$l`RkcpZXZeX^{(8 zyJq9AqG7jrg+fL)c#SItN z!v8K8-66ofIQ}B!s@}l>8kM4MKphS5a90>p>zdANFf-ttZC7aYvMWo+VE!0?h^;ufy2(y%U)e19x1VbC*$%AdEM51V^^bgmV^pXGzW9wUI0`D5?I*SFG1nG%Sa({tCpmLKHSasU$6ZnfJ7-; zEY{?Bm~6nBtt@`8jV1o3+Dg*;%s7;R4MS$Nr@Z%laWcE>#2;rpUkaPkGhK}y1O&(- zgV=BYyl|hu&SHUJDzXtmY&uT49VAIrDaSVa-eJ=i_wq>#w&yDTRLs;Z78kA>`s||N zrK4>D2bSM?w3-pJq4=~M9pVzPwhVuPmDm@T-jSG&R}@NN;b z%3R_|dFlaIDKVawzZT=m;?SOQFCM(3c5JG8YB@D5Agg&P-1g!VPvqo4HN~?>c^TUY z9w8onAX5Nd>>jvN&WW7A6N|H1578Qa_;f(jUs^MRXOVC}f2>JDp{q)%N9ujA z6-1h(F$ysRzyQfX12KE%F!axSNzVDWPD503k{d{JieT${%xBGV_DELAQSn4c1&zv~ zmB=hks(a3?tMi@|h~^+TB`i!PlJfMgG0&E~8@cK(nR$C40X0L&8;xnNUM!oP0yfqH z9-5hUBb$I5d5&%pJ-Y})u935>-QLlv&!V69F9&`1iM*>x{_qs`fKCnL_5zpI_)C=K z&gw>iTpUA&8stbk>c|tv`ud}Q@XvpBJ2!cTbDxQc)S7hgWci zrGFdI9KH4m(9zXnBK{*LhN6jom}ucumPDL-r0ADec`sg?!}&f6RTF%`d4{TMpj67y5oL?_6pmlQr| zxITmiO}*cdRt_ZU^3?{hKMm#A+DX$drMT<4N?k<(d3A=Y67xJg5Mn}xRmKgai&4o@dsgE>|=TepLDCF zy)7>P()bvMr1P7q@u5RWXJaLejM^zU5v*N;7*KB^i>g@S@I{fnU(wpD>E?dR@)9|%)^^g(>P z-q(I*?t7+axVlrYl|umD)M|hGsGv)kjJ>mlmdpsV8|Gr^3Fx2Tkuq_}$^T2$)qq?Z zKLvZCJlO6A8}AsJ_5r!Z8O?5TyD}F=kz%y|)YDyhTQ$yK&Kq`>X@S2T(lQ#4XR8l= zRY+V9dKN3;S>DJ144=OZY*1+PsEXl~CkpO46|Teth>sda=8cfwpG1hvW+!duc4%0J zWmB0f2T>!p&z%+FU?C1B{&Ld6H4@EKP}ahpZWwW<&2R)aPSW6njgypj|EmdVLtIAj zKpB&hj=P%htVeJ=oh=|nGnlQSi?7VrtjdfdP^~l{C09peD?^TwB7tx&BOrD9^}Rp8 zJb6p=%C;P!|GM>Mr#s97~zk(hcA zt8Jsu8Ej|V_m9Z10zpmiM)JY4$e~i$NuCGaO)L_I>h#8lWYHDQ05H^w6V_*7_?sG{ zM*xGiajeTLl8nr}bI>4dw-g`Vv9IkhxsJk)97|r>9=#}ZnpN>+aGgCr+P#m>FI>GUq(;3*!^bF~N7#ta}r%ukpq#B?W% zt%g`c6Z603CeI$QQ4L@!Y${HeUX_35Nl> zEw(atCO1PqHRU%sG`yL`e#IjU0HYUZHIAj;Ab|!WME+&quw z9tX|aU(;z!G%t|v9b!Hkmf_bhac#i;f?-~5!_;ytsvvk=bUUH6c2%_Zt^Z?vrBC|InaZVH041;sq<}uL zN#Ix@PW^F_$1m!djWq=^2{d>7V4|hOr!S?SkvjsSeEsv+euN!@?W&_@Hm2jOZ{g5J=%`} zIn2&dG5d)_yQ1ax)t~qzMU4YP8TA|tz_BnF{0yO4G?1|7;hgTJ6!*z5aAHV9LbKUurN@!m?m%)Y+ezX*KW z^1jRwinUiBqcr*~YOgY01@USw{~WH=aY9U-=JLa)>k2|?+Ucj425&Y1LIKX(;YWr_ zTnsdg#d(qlA)Y+SXj$s(iM-gp-_OlvE_|~H5261h3IiH2D<2jI4To?V2O(y{$)d8F z>-u01LtkG8j4kByfYzkS2uQ5y+_vQe7A}Al85qVqSS{OZho)X24oKXA&( z8sb`azt8$s(!l>cC+--nlv4GhtddJ4b*~>5TS|ic(D$g6ASsW5;?3p(iFW_5{7EWA-Hpx#)Miej345c3( zX0}*ut{bt~nj<^2=t6K%1_Ui)TgMht zgE5}sD>by?ognrD3!DVGMKo3dfOP}K=HkQ@-o;CQo15&23ZQ6PRId|VJ}K9OIpokT zuD_elQodubP_xQcme+o#=S7#3<02c_ROM`71cEZ?k>n{Nl>kGHCA@Lc!vi*89N0;5 zQ27oPYo0oqw7Bery4yL%>eG36S+572XB?5(mywy1?W5m?k*h4$SOp-THoJBdFU0Il~ z&nJ4APvcZdBN3LLWc4h4^Sz(vZVEi|f0$HXjMBf`hm7D#*f# zaEAi2I*rnc^RbPXooPh-6T~Sq)hdQ_Rue5$!ZEZam+L0>jz|#$kH`x;>CNcc6EaR1 z_$GnF3B1HB4X(r|c^$J2vMcd4cRam~7lO3442Seux;Q-DUXA0^&3R^NxKR9L{_u9- z?ggq;O#K(w2hlUEvgmyupNWq)MIKtvfAAwsn$J;Bx;!5m7`{tKmHPX282I+mj`fz@ zw^qH@bldv;d-gc>e@nI#zle%0SH{i)0F9wH0f0my?bDxePeV?gWN8VXaWDV~ju3_w zmrOA7h z`|rB^mm6;ybc5Bt=Fwb=n{3XhdOOP6g=-&Eh-nzEfFRrwR1n?dq6Al1mRi6-7=0o& zR6?d1rP|`ibnD&)xf$>^SIc0V^(rz>Gq{n^|My(#V3IjI(_r<>wsgm38` zC;-OF9V%br-`GrwYp^*UC^HF<}kx2ya_^??3~5it{9l3{+Bx_ZSc zoVfI^NtQi=$%yitykkke3E8FeAn>g1lWm?Q3Nsa?mkDCrnYjKpS zL^g|qJg;-JX4E1zMaFzKzT{%H94{Ads%oOJ0fMs>mnl&c&6H)g6$mnHWr2=_;ufT4kiPjk5C9JTyifb&#LZ zes1TNK2LWsMs5YFlG%mB%<;mL;ui2uAIi$AP&!-a<}cCF$RCMDB+!Y+$!1x9)pf=} z(m~W%{&u5Gyv)?ex!m>+-t?ySzt$g9o}T1bZ!Qp`Xi_T7ib|SDT0X#WouUZ?D!wbH z(5CxE-{+PYgqnPy_ReH8SE1s(7lq~S2PboEZ2_ZU9O4*}15MqPG8WJNQDG0k90q_J zZJDXp#|>q(oB!Z{B~m?1XHx)!LCAd+;$Mm4f`)qUBo`X9O^gc>thYu%ScSN7^e{LI zG8`8ODt?!U0owiDbVPd5U~xt&S^STN`5Twz2BrC(h)hkpVT%ts!gF(9P841@TaR5W zaAZkT;80g+VsXgs|c;2DY z6X#ug1kTYVVt5|hfAF~Jq9+(Pm2SSz32uBm?R|o5{db)4TB+@vDU@5?e@oX3(b!7$ z9ryY;AJKO6FM?+J8i+&7?s5D_i04MUF40U2cE^lk)rjlx?}G!l6~tBm(hLe208TqQ z0&Th%jnDi50ZrFjP_jP+F|J>hY@T&MhYFYIGw!pEwuV00JJ%U+KCUE4wKO;$YOb~N z)y5$Lkma@`TnhZdP)q6@xDcMY5<)?FbnC;DQC8iv-fiD)#KWBTyq|J(mq^#TYy-C)+x?N)-BY#l=L>+yKL8BaZ&yngLYK)p z`bU=BSxHpf7%P~_2}X7_L_4HG4hiV8rqRyu^4yO%-d}hL{*7j2C8pf;Ux1DRz<%jc z*ZZfJ44l@lt-@D`Zp8OLtX*?QOt)xs=SD-z`TD8G&E1a@83zOVS7*vx3CUrEFf|vSjFodT8ux$ZAIHERvgr{ap zN*aeNc`rl&Ye1nX5P%&Q08jXAC@T-Z;e)X9ktnOzOaphYa?7jHmUjGJY%~;s5+A01 zA01D8c+sv>Fz2SK74(3utfT(d@G(i*u1-^8qasXUyq${{>vw%{+Wk69U835`VKrdC|*7mhyLWBu4t(7 zO9NkA8JAL-Ea*1j3O42VsIYr$&)5VI-nJ_;3?C#UKWhuEx8`-#zpZ6!HyxEJOLbm08~7 zlxQ8Zj$6T(HXgO75Ec`&Ch4n1qmd9(6wW0xJ8{rJQBB}OPSw+&()GJ1v%dQ$>WAyy6<06;a!Rl09#>PCxM z%~kBVTB=ux-qiJ7)mZGWRfK0Ll*LuF*dSCO|VGyGsM(z=qPl^{K3fSEm&$bg&_z? zfaHARm}@6G6AxUV_b`NERRkcr+TpE*Q!dDqz+jsJGESgJ0JF7o{D=P93!ubH=Y!fq z!Ob_G_VMHcBx#1KIEUda;suzEE`|rUxzd6{=M+6K{U1UFYd6!_FGNm=UMxxsQ#f@F zf05vslFA3&14Ii2tV@2|elblI&|CD=W1&=HXzujra}>ZlQrpZidiEwCeHu>LC>`v@ zYsnQnscNOkMXA!Sv45*Qo}m*6$MYc;91hP=cS&}u_5brqYMS?}OYCnxHURhXzxtDb zwS1>WfO^_`sc?8E9G)0R%Yf;X?Z&9;kx?z51Q)2x_Ai)rX5_wy`vZOwHRyqU-nZ&i z|FG=PrW2+>F#yXdV&!_ z->Q=OO?ugV zBzmqKzJ0^6fA$aVZloyhwE4c*Ni=Vy0FdP(JOE(Eh*fP~Zi3)BtgbsT1qXA@gcLyJ z#8v=C)}1JhQJe8yE`>>J^PoBvblhtHD}fOr0wN075{WiMmS=)EjOkiM^o-ZlQsUQtgJIidEw^Vgm#I$H?Ee1VJvOv{lh z%Wrap5%Q!0v8=o2cbP)1qt@>RgpipJky1>r=kWSDRbh>z-4C7h+r7kL*rhh%1f!Zy zWfaEEWj9?4hGWS69>)$#U!yK^)3@s6L^@l(Z|ZMo|6(8lW2!2Dgo@4K#m7E}9XJ+V1PsIK7NB+I5Mh*SVUeupSru09H?zwgvJg|OYX-2S7y>>- zl6e)G$&K>%SUwfQ^yG|HLXfLJ4WnNN+k^nGfEDpj_aD%09~QtiUskf3XwVdM+%g*D zTzSgKNCVzHSjC-`w$m)IHcF^(PL)`OO@wN4XuVYlLV+`&DRHCP$V^jZ%7!w=A4)1T zv4ob*U_>msuhVp#!;IAt%ibs^Y_c6=Xg$(+`gEbUI8Bv44{C6Xa2Y~z-(W+T0J1gz z$I@8_w81p(I=E9L1gF8B;#MfZEw~gb?pE9>!QI{6rMSDhyA^jSrNBc4PWpZ)|B|0G zncbb8z3&SXW&kK$s5cFQk~A^Vzk$lZkC>Bqe@yTL`VnZyn>#YH)x!3|N>vQ86Z+i< zU6_Ur-F;F6-`HsjnDQoO>g@D6L>Y~u4~yf4E&Mo4GH{Kj6Zu6-Cz3}%k4&>caw$Ch zbg@k}*@&*91l$**ZvbK?M`YCD-Z`P3wQ?4yVIF)b;8uMmx+C(ab?r8s+tb%s;qjMy ziIpF!pZu7d3~^$>kXTJVxbe?4uIT~N8^i?M5ikpQw5>X zPBZ2MAoB77MJTy3W@rcT8Ax;hLCa1+K?zzE94dVoQbg(`AkX774!iiZ$;}vMf|SgN z*H8za0PC^7ZDE1JEXMnPd1X^&$M6f>uZxDG(#J>(>RWp4NM-rP1@>AyMCR_ zj8b;IU(qca12f!NSKGUjB~q?{vLIbbaT+4GW0Y&uPbFRYudgEYH!W7J&%f5(XRJ)~ zUEbQ>^n{l+6#~SFjwJveg7inEs0Gha)%lYYH-A;1HwUgix3c-y&r-YR^Z$;&)_(o? z5lec(aAiN$4i>`Ja`iX+k%)!7D?l;K-Dz zoL!#Nmm6U^gHlc~1yU4HOBP_jTRY$w>ipe`_9cybaKCaTpVTc$sZT|=HUj$f)OpK7 z4s3VFSCY$y-=`#%OvVLP3;j^QjP2d}kYJ6qw)5@v;hu{b ziB}P`NIOT4$IyUKEY)jtBT?EAI};Q9$<$_uEZ~*(O02!9sa8kTjfkTJ=g}8VkUN3M z3&H?XVff7DQUEGjb#zDu(vdheSQ9B6O`ME!{aF=B(6)x3R+LqOrWPWu!A&cSSN=ur zu(Q@uVpNOpQ~KjB@W+4Kx%*Zz`y3ev&Y9%+av>NrQAk?4RH;iPjj5?>xY$6VEQ69& zcDaKMx)rjHkG5nICgk!F<2wKG7z-9wYjG^`YJ%bJJ$00?KF$`33y!DU(Kh9H6MhSzUotsq;-a4kw#a^yc%W}UvH7MT!Pr&j;yp1qYXH# zFugtn?0(XMsi=u@R3OPjOmfqVqfA9bAa(IG5_D6LMhKz@6M;=+oPyS3k}yROv4~ZM z=bbLrmKe=!B{1QhT!mMTX-PWc758^#sTOqR;^kq=4D{5-nh%LA7Mc7kdE=YNOh#^Dv#6 zm4_5Vd41wwFh-$%Fs;%CyE=4l0RAVz6SH@VQ(BYlA1{xuvtSw=7A;h<@2(A=$WCs=Pj%{qL0Fbo9 zsrkq`u7|0iWGGR#Mi`u2%l*SM3c(EMoN#}p(orCpSXoq>)G8)jw|pcFiqEC@F3EC3 z+}&K3xH+Oi2ZPh9Xv9YvHs9qS-$v!MwGLh>cu<_&6`ST(eCZo4?+Zmj4@LU#!t;N) zv_rV~AYbLGl$fQS=NvA@ac8Zxi05sT$7oQ0^inC!HbpWdwrZ^G4d`q8T&y@KoYTu? z8JV1oT>X1Yqaw0XZMBK^a)LZ#y>eQu)g$#@&5etpHmPk^zSq`h^Q`Cs4>2MX09bhA zKR61t!3zzdV8weUs0(Rb;DCu2l}_t8Ly93w8!tLCZ>jzFkNjxFafhM@Et3qtskgIZ z6sntDCK;Zk%_kf~*Vvdd>%A4?iw6$S+^$w%cb6q4Bkhxto6J^c(P)p1P#Lg810f}Y~Kim0wLy#h=S8?TBgCI8fBB{p@Uol zhx9Jn`^VBw9xDJqsw)CufaP*U6Fr3@Ws8iaMkog;HxMye2B>U6yW7?pKp5o-&nMus|BY8X!de{5EGIyZV$vrFqHVJM+kAi^ER@sW;x)KGbG^@u}6;q`H((6i^KY`n&(f|~Lr?vBV5Q>L_L^Ho4{|6PqWWGD=ue zdY$FFqOT%cq0MvT(`Kxo-UgqM>b#gAI4Tyil8CQyD5s}xh9gvX$Wa*pq-mGy`6~-N zrH(UZP1o>XDH_@t!bEJ2{xgUPkkp6QawpHkJ*O&4wX<&NQt^#`sz$$BClku<;mbn7 zv-wt+#os@>7RHBT710bxTnlBj4;R{7Gc}@YcbQ7cJ08?o)x7TqvdFdM>M!VH67jNw zF1Z`@PklTBUYhJgy+nQI2dI?#w#STn-A!1T11-|pF4>zzstcuU{Vw%adW8}k3Q!rcx7?AA&!hhMCU}bz^I7O0=dr$ zvGEO?t1iotQ;`HB6MY9IsE{&5T&NXw31!DG)?>;?BUM~ghRbVN5JgPVGWGwDC3FcR z6)%*(?n$PZ<+T+}d&5gZ3wiXXwm{HH)g6gYtrcQuBtzPEa-dffZsK|UyZg%Sm%ox? zkxgD98k)<1->$hyjebejhNk#CwzRRf^^onq*>dbblC&5Cbp=|_P^&yM0Zc0g7HY)6 z>JlE{j|sQgjs-(!3G5KANvK-EI7oP5X9 z+rI8*nd|WQHiUo|2&5;rvikf2`f;T6%;xvx&_Y`=p(vP|n2jPJ;17LI|7n6&C~q@6 z2PRanwwR`L@^S9|h|bEIUeU1}uE9Zc57Sh9`0O23q)cH3r0B-y6i=c?z?jm5HhXh{ zm$x{L6%RUegYjcm9cQW)VJBuzT^5vgJppF7uo)$jub zLV>$FH*jB!!>{AY$lNr8$)p@w-{bh_1l2^9@7sXfs4QXBDb;+CMQmj8_&}-=bTaV1 zFCd$-@ta$|0qq|OlPjmFM2>-hH!L*hnqY*BpIHdt?_MU$76ui+Dpy!8oxhz9hLQki zQ4xX&#S{AZH617BQ@L5NGFP=RgGNv+WrHfv+%1-e#)z75+zV2Umn4tvhogr z7aDX9nNAv=OY8?tL4K_&3Y0~9?x$~+YpglU4C$G;E%HsRx(<(qscZ5~TqhVHfB7@% z{+PO6S}LD@=oF*k_b0#sAZW_*$krwMMkUU0yV|F4sa5df`2o=f0QeNBNcaFMDK??u z=0G_82K80J*rRIMZpu6=PSHLcH_E~SomC(ik%iW!4;q1zY`8c=aD60FS%JMD?dQ6+;!?W{^d4B^}u34i!V~i&_ zAtwW2;&+^X$?hG3O{7$Y94U;Pq@M||k_ifgj=+Y)GHi6(jgz9^0Mc6CCamlh`;{;y z8e){D$&@j;1f1lO96i+WcG(oDftVcj_tjVmA5`;lI#^=miE|mBTdj|LzgHq6BGB4F zGO3V)l6{hz7?C-pSP81)xtMA%KHeT*XU(4Sg-t!s#dMvezdaUZ6`(Bs%uGF-8I!ug z6@s%OX@VpNdX%`#=vWZVZG5OpS9f7#0k<(GsXSy~Sr?KO8ejBdjxOuQOWeyd|~x)`wjWk zsP-v0Z}yk$9{e7QVHlku5;u)0Wu`qDoW*j8<0{LYdE!tJ&PEr88F!)^i^>>O_7;^I zDKKQvIl{Cdbe}1L7Y!6foGU|tijIsQOl4?`oCkNWf%MB^WE3F|O34z|P$x=oItK%= zg~nmFMJeH2rcNtPg~;6+j27aF`$|a@i83Hk_`5Mz;(g&2U}{|pzt1*JoI174-oq4$ zdxf?L)uV_Lxtk4PlDpT?Dqm_3T1%LA@E!n<=D%QC++Ys1hz~tGFZ$mEOiMqs{5h>x zsIT4G5w&~!T5A>7FbS8yoPJsD<2aTNab$Sf4ZoIQGwCuIyydy&tFgW9UK9BCy4&|u z{ls#U+%rURH~AzcdMS4M`Vx@(ZP)$&6g~!d5u3Yx^1jT5Qz`Pu|NZc<*|>la)#gjK zlmXb5N9hCJ7XV)FSNr^KUjlYdpVxaP5h1$hFdfu+cigBD_3v^C^N)u>KU5@!4_uk6 zyw-PtRZ%jv7^G*tY zq!A!U!Nw4D!r5*-CzB*-9C+CbR5dTTMIx7NLc!3;%n%%asCL^lQ_LEl%E(D9y`3;{ zqX6_yo#A2bV_~B*g3!>Uh7r`}gC0!O-Yea?5FIiVelD#iSmE3=fw`g(a03u%BS;tW zY_O3BAZtfr_?CAeGwA~LUj`thfN_8}qc*@8+a#>ZHX||c>vjOR0}2p zL=qYRg#2gMX@Ot}M*9(Fw@#y*?AI@Re{U_nv$6-5`V==_wRA4UI?7zAEY2&OTuoi8 zL2m#4ITr}P(OL71OOVRMmBMh$D(UmyebMQ`*~%#|&Pj9mx?5Js1MuvfVaXeght$uB{Oc=cUXQIZ zudpgrXh`=Pn$6In5!j7ayU>btvAfRR7eWmsH=RAWHybki*>FAlc*Q}$CHXv4fOOMt z9nkz8VUy&D;b?!bk|=#EKwx{kgwgplnzG1ucx{xA{l&;M>vJqY%E}=Z>+G-z>SybB z$T{p+Zh{i@F-p^E&cbu|GkJX6(XbG9+Jjt2Yu_9zw#q|lXiXKJAG&Th78mtqR}XdT zXRormd?Uq88&^W3C4p_URXTP!fk9043cotY41!Nvo@` zIulmLog$~BK`o1l{#p=2rr;8eXNkODxqcquNl&D^Od82ud3;CiL~QqK$e77}$wfoH zrdv7tOU`$@qQN9-zCCxJpDp7KzZAz(W&Rr_(t1lB0q)r!q&)&1@(+OdC#?Nl(hfWo=X^&50dP)DBsXQ ze?>>yoBa^fpP>SUV((K0o&Rop;}dI|gv1h_~NADG6{2`TKzcKV!9fxBtH~IdQ4GS-6=2{43VrRuLi%KVu_??aX z*!$Z`UcZ*s2yN%`!;h>M0?FUU0pv|y*Ogs7&C@%j)Q@2XpEy;lULODiEy6HBkT8=G ztwGW~%aFGd{%9b*4MP+Oc3Jy)g8GDSz5W^gepJ&**j}6ZT0tjENd};t8eqDJA0vTx z7b6@+^?C2VFGYAIJeHREa+9Y8|A{VH&kl)O+K%ot`5A*m@jNPk9pM$eLdKOZc^reO zfpU70c6h!SnA`^OjFKI({rB3m7{?i=DnuBfvvOU%W3R8zO&^)9)9c@QCSg``h@EzRa%j zndPwp7+v8L7SvHZDkRvD46O5tKv@`jGD(LIf~U)>P$&cFmpi!qcPDuZ%PuWenGsEw zbmg@XN-ytku5w#3jK-&rK}Qak1j$9(aN8Y_+- z;|NPBK8AUUlUo*B_<%$)iOGf(T?JEZqJ$4G)}~Ti!YikoIGmtQzh5P@bdR+#zw)_^ zo7CfYX30um0Y>b-fD~h~__zpo4B8YF!-2TyvFFy)i!aJ&!-o71+r{psb3gx}An~rg z5MnBmY<)p6=HXt9tjHA;HN+$*e^-x*pbW-WFinkC$U+&EwAX3O zdbRuYn3}qgXl;=)%QU1!eG)}KiiI@rBbE|R!|<@|{kE2TsbYjV)sW3kU)R~iOf?y@ zV3&`RlSzm&-bpS#()_#JV!Ck<5eWK8v>eF?xKs3WgM|~DWL`_Ug&4YEKl)-!+?Oe``PSKGd$-y7#mC&j>ZLXNO94ohaKp73gUvWR7R2Tb9Nk08n)+2nASG0(QVwqj*-g(1aI*bw4s{%@z!v z2`Fr+f11uuE4miLUfCGD_!CLjjb>3rHI)o@YRW9Ho~drV68bMe^Dq#8w%S!G$weoR z&0n~F{gRf9tJa-+Q>RLaWgYJazeqCCFx2R+z>sJr2J&!;mCnaPC$DG1@qMRHIz9FRxGEUWw0_Ds?8AsY}|BbmN36+LjxTmWsRq zAh%|A;)J#Up&~(u59)qPc9&C}vUk=2fY&P#!CCWl8zx`OW`;&y1zwUE9LuLx<&~=M zLIfKh@ZA39iTYZ8HRvrYKjYrI7R!D^|Bx#f<&$I2eNcbys%=dYD#PDGCpq6s&;XY{ zQ=eoyq@~6Dn7UYPQ}1!V)fteCLFvEy$vY4yTHr8_O(p1U8h8=C<~g+X_B-cM@h2Yh zhPYyym1_R7o6yQ!(ytF2C=2`GhtJh|Me!|ahb+z;o~t`MlVfHFU{oCsX&yV*fWgb$ zNLacsL}1Smr*c&d5f20ALO2-0+7kY8wzx-|V2`hq9(Ax=&AI7O1shs|MR4Un+7Kqt6cSPnKtm+ z^pqF=;pi86SL$sP^h{gCMXa!>M<9{ALr$iBS`^J z)Nms#?cS}`Xb>SXW3TofCRHUO%95j%0ShQhok}rO>5HH|j5A~IZ%vMjHQlb_3Y!^F zuuxO0!izF#UIHr%zkQS$ z5H8mH{(DPeBD*%z+rg!^q!9r*G~7e>I{A8l06l^`i9eBd&IUj$ae#!wBqCT;fibNR z<<9Entgm<3T1g%)|Cwc2I7%&}$R~7B3>0~xbVf`DiXWdSW~MbUXH!S3<%>GkUW^~U zJ3P-c__DY{^b=aF#J*uiN#6DQzf`Wek<})mtJAZSu4m%>;D2rBe=w4rZ27DDm5Z)s zYj_2T4A+(uVaKd;lLjCD(2-(y8Y*Bxf2n6EYNx{RK)MV9QSFg}XJ&{Q?f@}U_?qu@rq40VnIlEyzKN7SUh`9ANSU7_LBupJkd)YH>b z8E8m8sZ6V<*;urP1^JImZAMM0QjMIeb3W{b{Jc$w{8GIoBnVofRG_XSYR{UhYSfHZ zgYMa~)8J};eo*Ub@p3TS{6U?q!sK>c8Z*tyYt!P;`-GQX1T4RtVE0j*`C6uT&P{LB zNW=M;K6Nc0l8PfjBZ@>A;$|lG*Yod~eULezi=@FCfJq3zl?;s37E!H7i7r#euGcOb zC}FKUaVg^DDClVBVv8wpuW$!?+^<}3aQ>Phh(LL$U-%hj`Dt;8&nm@#R^zXVoz@&> z=~pFHYPn4RRG`pkhZ4Eb$rGG}Rr<2UzNJ^g=NPNJV$!0M`Y+h$FyKNyJlL)m&5i$V zuiV%8O_QFrvbE)-74^2K=QNKeJ(-PjeYL;v4$6wOlu2c$toE;Rx`L<~kI=LG{)o$3<|mc;7s%d{Bxw-ms!W4InGBj>7_+E zwchNMBum;Tsk&5|A&I)*U-i;Z-e9K!SbJI(o4U5my)Z@W%Z@Nrm$W2f6X5t}Y9tzJ zak=tf+e~%Y$O;jq;$LTH^PUMG`{-RlG0;^J;&@6grXjpBkexRF%pN zzhMB2LkkvE(pg2j+w*ebh^&=knt>1(Aq5vMVrNI zOs0esg`e|<#w77A5U>@(BuO|4FI@ zE2k&$B3ZLpx$1t^IH6YAZ?LHyR7o4tssdo%v@$pOPE&Ue35wm16I!@AVu)jnqfpa9 zTnGWf48BfS=$!{x{OWa@8!6%qVISOxfdqlbQ?Ve_P{xQ@%%}+5Iv@>qNak=Exi0C- z#EIN?WJ1SV6Vw@b=s8pSC+^OV&yEbsMTVH#>y9H3J)(ab@d<#)B3-hk-qW_5*V;cN z%Ww8)`Qk#Qe|TQw$Trlk=6wwRDr2lw{DL~z*S^>8@@y}l(rl1$z-lbA_{in zEN&FX>i~4*#EO>g-a{Y`{lm&)GiFMJ$}}U`>IWeU-vyluCW77-gMDE6=^8);=Rt&N67*3(ARx?z#X1xP0n<7>wBN)M7f%Fy%F65< z14c(jPCzUi-(4oD{$)Y82VSK?eaAV!+FS71J2)&O<6kwrz=(+Q#cE0ktCpLs9vl0S zW90v9viS0~Jta1ndgJlSe9VA26q^kQ!Um{>Xxp>xSC8tsB2XbX+mL7d3@^QFLPbOY zyc^ckjOE4;^AP&|S{UxUOX8W4=F}7kYdCh+^8Czx-}m1avDg`tklsGdzMQga`uK_~ zX}W9b;Xe7_*InL5ZD!iPr+sOT+4&TnrGHFezxzyzco}{zdH;Ahw^CSM9?lp3ls~tt zd#Ur~X6pRm8@x05?bfw(wtC;E=wg}0^`6CfuO03-0sq_>uH6g&et8_(-TzzwfMG5g zW6}+~F(4sL1Wk~NsM<)0cZrvSuX2B-@t$!Bb`R4OTPIEH36M>Y$g!C%aMGdMCL#nQ zq6&dB?e}KleyAZ8i(_Nr{nyXgfc>4v-u^t2vn*M2E|NlyV$TMqV{CvofXBpZD~_4O zTbQ{2AtHA~lXEbG3nryNq^8Di4&@v)jbiCm2S;qcH`RVP37ehc9qaRT5X#s{Ih%A$t$>7umQ(NLLM zGqmZ&B?W6o`6D9M{@>*V%U18T${%{{ew@_5{(X6_7Wo(M*CF@2tdt)-;vKj`CY#IK zY5zmYc9@nV&3SSF$JxITIGpvZkps`sO+g_hNpoXF@rcP!Q#pXiNY?=YXfxejlW z>*-4Bjm^=P-|sFL?^)rF-bQJQ#HH0yYj#l2QE2XeS&u*Tb{}Rh9qfEx54}e39JV}? ziCrwedTYOL9LRdVWrXh>-=3%6>wk^V_m0$5x<-z)ytlT)84b8w_*rYVy!TI@0|23G zs1i2Q@o*TIU7jsX_BBk3C}yWykCz$6+5tpK;2#x{Rh{W8NMyk#+V7<4-&N&_Q>T7( z#xD0>$7CgH)p>tFvD0woM(^s!N?@cY^7jVz5o=3x(f7?H}4(>92K=`2Xt?bph{!-KE7(B)5RAOM zlny<_QIaBLJBEWPYrnB<_3^r2ejgRs@DY_K zKUU4G$jV65;Db{T<^D1& zFxyNTig_eu2Y9r;2cFSU0DArg(Zv7|G1swZ$r>Wl*Q=0#^zT%Yz^cdlx z2t>LAi1{JN+n$EhUl2dKIj?7%S&)ngg{sUJQWc|EV zxxy`V>-`ckpxWUky>uL#+nFkmNvX zW96Y3;Ouut|Ncb{SBrFb+2L*6P58;FPbv1}bIgmq%4N@oKewwJqCEEjUrG>2^86I2 zh>7*|TGa2CTa8-JYliBYlWx?MCVo^9;lXAkD{;fo8)s;sVhM!!)M`F z=DA&-koKUviD@@ICrzp6ZI6skxD%p^YV@iVq1lOie7y4Z{}S~5|4eE3Ll56HTJyCv z<_4_s-!UcB%fUy15uGyJOTovze}BE)y1Z6BC3SUIDlo0c#6*DTSS6c+Dku(rvp@EZ z=;f>j*D5p@=#@2HEdKoSYPO^}i$gI(U=OJI0nqpG^$w-OCdu5-Oo_?VLWgh}n-m5i z_sb5bnuDC_Bgb3yLyq`ZtZhH4kgK&LD6eT$s>8*$5r6WSD+Y$r2zp^P(|f)5onSyq zXrt^FeKU$o!c*bmTxZc^XgZAt38kW9u5dGf824LE$TjUCfRWD74m9=k(K8P(^<&@V z>z{W`_E?lO;8ty^U<<;NgD;bk7ai&K8;b9l1ELf!COI<=qpTKx`6W}8(e!-Fce&F7 zAnJshqEI&7j_M;&kLr8@0Xg3r4}qNo46cK_P#2_s<^s?fVF5OGKkd_fs#~)!C zli4&&)k1PHq2E5H;C&# zg$vlEjRiUBKA|cg(je%d4}`JpqV1;OdYD{;D1G)1hd4L z8bmG`r$k2638`H$r0Ugvwq1Gcg73XgSpO}`p<&}AW^Cdq8E;0+X%h6*BmxQ6JCnlr zH{}y(9Wl5nWinf`lx??HYg9h_ELZ`MtkYBhM@>qDvrrEt8RRYaToR28AINhA%>cCH z4H}Zflk<=nHD>1MC@ZqY_%0@LVJp%LIR5QFY zzZEa1$Z<|wW*+T`!au9DeOg=h@@HvJ%vi1xsenoStA;xOacZ&jbt!4lOp|p_8N*D3 zoLwz)c)EYUpFa3e?zQjsag`s}I9*5>!?@qrTzG!mjcSt)$iq*rG41^718nMp^+xiZJdWiop>KC=eETKhxAC zYU40#y+YAAmdESl_O>VQ(_7`)k-?h&ZNGo+(8x-?{h{>VZkf0U5DBuRECVhWGGUe? z31Aor1``IRm4GH{AqVEC+DlRAvrFks-d{vw-{)xQ_L&O?J3cl9UABNJDgw!_9Yp8} zwkpW=tKMT%e3|FsE7@GNY1JLIo_L0q2*v`G5?6{P5w1Bf>*Z1?NHh}|g2_J1*^#vv zy*ewhMSY5vVR$pPm2Ea0EG0f1Dp_V@enK1>%AxnK8eZYmkPdgCT(O8u+~u4V^YL^*_Pjw zcUHfBrAeFDLNxI4aR?GAAp9ntQY#%6lSxG6gy}xYjy?8zdZ(`UuO3yTI^Jo@6->lG zf@KoaD`xpma2mUf_+K|is<0GVa!f*w9Tc*cGfb(HEeY>mK$Gq^RRDlx1Sei`-R%M zkHMtQ07Y0A9Q@Q_V*--VeXR7q$#*zbFpaJ>{*_Vmpe-)!m87)BV zW64MzW0hxVcSff!*a|c7*qc#JZOd}#c-OK$45D?hOX-l=o%+ro9NRlP-1|l z9W+L!7oPKiNT3(N1|sb_Iv_9;g3_x=l=G?8V`Q4n$M@TtcvL3cnJJDmDLd9&{l4e0 z@;q#;U?52zv}PiIU)?5}Bs~51XXxaa`h#!yoRkUvV~DyVveXmEQ6Q z&=nG3sdW34RE;aJ8@4tJ#}SpWDiq z^BH9#idRwtuYsF>gpWnf+TT(8wQuz~pzj$PGMkY6fo%ae-$cjWn25#7`^;VIlf|yi zUtOBmF?!X31kJUb?}LKzd75(8P381{1;<|CA$+qT|MmNEkXuYmQNYNrq$5AN zv3P7*z{1LcU7^TQbjgs7jjIeGwM}Z`&xwim+r0K73{vz?rPtmx(S&A`7p+N?8#8qK zN{qZ0k?UNb`T8J|!XG-xTg#9XMpO)Dbr2){^C~0Go2=KmP|`*Ir$xP;y60=zpS~np zz5oJ?bPf5wExTbzPGh2a%*kXRa`Sihep*N&8hAO8&zG9)%w`Jv>kan=_fJWMz4if< z3mybHj|WxQpca&(DUL;KC=_IZVS2LVe}DHcL7M;&e!AjS0~gCmv-Lw7{kF&-S(e!8 z11ShHGR#^}#dM#u3T>?*H+!H+A2nF#P6}_hA_lJ@L6vuf3!Ab zydEKNTs+~qEVE!gLPwUqlmOVolvGLR?eulDH$EvWV>zX?mbeEE*yA#cfx#ut4$c^w zO)7|wwaF(v%vT5H_VOZ-#WcmRO$v|R4OR)N1eu2j(S7?Mp#|k(J~%oz{-7M@ruV~} z<+@PBBq#b#WBE+#2GfA$M2iKq6zA$LZcJ?+Xx>p6dToi_nWqGqPSRuEPmZqsMp6C_ zy(F8$PjA$szGQj=isCEAaFuMU+n#17lm-A!$xSiSLV1s9%ue8_36Ec)EC^a*84%RR z^uL1@WL`wff);PRwhaJIeAJj=Cdo+uDc-^*YyL_ii6{#D+KpjTd8=LnK>qLq)h}F1^D?!hXVVdX2;mL~N&Qt? zQ!-q>YGyM}2@}>e(44{=QD>N1kQx~$Bp`;=Tue&#M<>p0eYyG-k9qxoJmPrlsyK@v z`L$8CHZ5k{tp&MtS5xYcC@=GwJo_2NAdCzh2H6y|P zKz&DFoae5DsaQL40~>TLd!zJdcAD)HE+k6PGRt=!Z`zP`<46e$gjF+r36K?kj@4Nv-rO`@oF9*{V9vlCXY<62d+C<=qlVUL)>lkl`@gVJu#1=$0=LwHnBP_B7-`?e#Dsafg>Utd-NYOMlHC}u2BLp zbUbTPSgfngodU07f(i~8W-+kFc=m8b<6U||Rv(W4ycw40{&vF%nvcsZCbD^tQBXv; zteW_H!<@UpBGI(ggo7y08|6_hnpoByjVY_#{iZchQo2cuujj-?=+`Xoa(USI?x(*@ zN1R+B_3JjiE#8(=&aF>PFKMN8Ynquvk7JMSq9@FL0ZD?~($rYJ09wbb8}5+F7*GkD z@ggx3DiVnV8-*^01OoL0^7bnNdIE-oI4MmoORyhlku}YrF@-c|TYd;h4l%LH!AJnj zdklRaueobV3x#nt0Cj`%G6rV07Vp31>H)6fm#Wz>ZKD9&PP(4&g2aiuJ zPV%eQ*8M2cDN%}M%6JeRTO^9I!L;6|eCET$m{94U0f6ogg!gTIF8UH8LhDq`)exOx zK}|O_I{XM$q8xODH<@G~Sw|bhKg@z`S;}idH>|Ko+BqDlj#&f-|y^a;E*l{McgXo+ej8kjdv@s)@a`uBN4V!hJ zGRcaIzTUjQ{dt>O9j6{em?Bt4=Qt7ISjihtvsj*KA6Uo&VkBH22n8~+-f>TE-(&L= z0Z_XE1lLX577!pz^RNktZ9yVx1R+K*h!F!Zjicx$0rtY07SB*-r(jqQD*z%qIZO=z zdhAgO#bOspuhqL#g2vqcI{G}NE7QJ_3KT(!^p=@03o6rBb<qTd?je8nR^UQ^knY{w{TweLz zn*CRelng`dq@x|VS%;sE%svl>Jw|Dl^q6VieNnLE-{SO8b=G70vZj*n~?YXLYymBnGs&=^4|H z4J&vT>>^=buHA&J{Ok6s$B5?Jz9qZNC1N;G>W}y1bJhc?q|ZECwCG54?`I`fM(-%L z!2cf9myaI=*jNRHrNrMN(LJ(pd9GddQS_l`>sD0(==}f!uCBX!_ah<%UV_!V$P9M< z5rMT$R0v7I$>}0}a@+knkECMN4uZO^_(WWsvq8V#Coy$5(yJxhlnS{MBt4V;c9X9z zm0B&+{f))}!%6p>C)C{3@3-D4zCGXiph6_z88qM*=9uPpGiH_=%1i>2 zVUjAidh-wxv_MnDc`O2`9OYRHI++xbhmV}Eca+)~MKIpNN4^bSKI zn`CsR$vCsRO8Mh4_r@WV((r8y;?PVx#{)++n?hY-W43Oqkl-N*#K=4OkzpXF(;5i2NCGS=#h54Pt) zA!$U|_1oJ66!7O(Mg1hOiAhFTzP%{+Ky9v5wci!!$FZ%kCCKWTZ`fYdA8rEk*18ynPf&GZ=XYw~&-K)bqeWOb)+f zUzzjRSY5ZQ_7t1(pKE%|C*5+|RIdG34G%Dof4E|;$kIgz&v{E4nSW2Ke75ih`*Az7 z)5~Uq^WpM0nRg0})yE9Bt?veWw!e9-Ll8dK(e+gJaN^w!8S5iTg+V%^2uudT#5fC0 zut~sKK^>(*a7dy0DuPI7FIG@iB4c z5)MVOhKeJJYfm>QA>wimSD}fqlLaDWV?pGBVY2k`Z|dKZaLO^H(bQ!Uz$t%N_$B>W zp~8_C&Xl>eeM(rV!bPvltXm96g{>5g@tnJtk@@GFZ-<#K{C&NPO?F@m zdhB<#M93&9k0gj> zPbiI7Q^XS63K@^4X_B&t!AqT}J8xl#s$R#Mmtdy~Hr}DOJ|5zfPi$O`Ez;5UAxs`6 zEcL5Stbp~J4|vnPDYF>V9htq=CUN?&^jM5K_M1^P|)~GIwJ|Dj6P3jR@&9 zm1>1>=VOOo=k$!9A-|CLv*hqjuIP+qO;&@vi%6ztc4S7HWTL%ya>{I#+#k|8cqaZ7!2(^d=Vc9!t6ijK~nwT2rZ@y{Xp4NQt88+}2zw7&(?p ztd%Hh>PpILim)o-9UnBL2th(f3SWL&GKOu4;}fh>)7AWqW+(9glh5~QwLe+Xj0P{Y zJaimcAg)YWMm?rnkK$VnfnCEGX3JD`)cZcOMCaI z!@;yh1>i{%KQ1=R1(}3K8R4Nox*-=32HiTVoKD6=tsuTm$_Hu`O{|3P9jtURIrgcV zreP>PYRQoTg(HsEbNC4j$kx%ct@@=Las(X2mlcurc&PHRxbabZEwlBJJG=uRY_Cn% zuK&l=wmhpi@ZeSq(t9G#(KA<8cs{we?-ssu+ogzjE z{X5O=K8#cnqh^TveBcKhlu5%jy(}+=s1{ajEDB0C(JIA+e5PaGddEtMFGnZZ7I5W? z5Lt~9IP>;mUAj^GHPU+&HDM98mv8?64*L{>H(8?elV;U2r_~|&YeG=wvdcBY!u(RP z2+x>nOKZuen{=L&`e!Q?mx|H}5&`v(BdmIYZR`v3y7{^s8P!vF(S;lJGl~VL!UYO}ADnEB29@Y}t$L!ODg1YasnvwrOBbLn#SeEKm3&7_@%} ze^J2LwRr1ru~|Cv-+aeKSskl$v}~PLhf61S1#GzwjfH^1RB4se%Fg<>@a)9%6xVOw zUsc`#Ppb^tJOE@b9~JMMt#9A$58HD`#d)n1v{3o9htviKzQCXpVMep{l6)ilU63vg z4veMLzuBroBP+u(0(RZel7KK=^{qbbcX@2%{n^z1UTG6T*d*i9`k$?i=eai-SL&0B z!f`Z(Of1YLT9dhObek0?8*An@#erU1@4v%7gWx$7$kov-S9d|}V4yIvMDNVwR=TZ^ol=otG0x~oZ-=dZ?w>~Gz3UHsf*9a5dn+LU{lCUVK4 zMdy}0;v^l7P0HSTWV@c<-@FRc*h|`ZyyW(iZ7!@$C<2gg9aNmOwk)IU;ML6`vS1J?2?@ws9YyLd61HR{E*|F@ zSI*?dEr-4b4!+Zz(WH9jMD9AK7co`x7Y1GR0pWWPQx1^6y-AW9L&i$K>aTw*hVV%{ zDPtS{#=^r{j|)$>t8=se^eI}uq^$4LzY6B`pM{qUG(jFza-BihRX^V~Yi@sy_t^Q> zd>%g{jvw{;bFlbu=qsc&`c7lu`N*@X$3r48rt_M->+~{8+LYGg?%T%r{75m|s|?6* z>fl{?cZ;&W4v~k%S+B`jX6zL~u#xyf^d*2{;uL!b-G6B`7c4m^iKRd3Yv1z>Ziskg z3S?L@_!bDZGuYM`UD62K9}`(SWktu%ef@n~&C;-LwLOg`;&*?B%RaYuQT4+Vl79G7 zyJgykeiwF>B!2xZbty-=H^CcQb8B6i2Dy;I2CZ*q{esO)oep=6wmt_7VLjSSpGuL? zNpAN;y6V9}w{Hj8jXY;u{vch#5 z2+%rk6^or6kk~+-)zKjuO@dKLKoF_|PHa_4iiN``*E{xXvL1HJNi`Pt8$meUsh(6o&eMYZ=bfffaA=&9V58BT!xuI)X4Y! zovb1UfKXG~P_5aCEG)4VUz6X_ zDx9^Zrb)+Cl5MR&sC{RHNPUEWLqPVw_KK2h+lN=4?T>*X=MC;LVz~b3IlBcNeG~N? z`o#Nm6{T!Ms#jkq5`8r}x-x95MI2cj770Pd2ITL5-%S9>rBOfbJUhkzcqhbax_8b7$`u90*s#W;l*$!RoBPqn*=tr79@HigC|eK`sl6vhGQdSBYSU4 z+p}OUtI()2ZW?N(N_PqQDqFplh_&f|Pxc7}f3S#8l@_P?q}7gRj3|hRE%}sT87Ws5 zg)J^h+Z2^En8J3mi&V_;nQ^Gp1wwRxTna%1SMwd%m8(x_4>O zoS|&*ON?m5QY7kZK!@4Q-4mEq88Cr3O=N%)M+T|WCZJM(CB-5!^ShR=YMZswnjv!D zh#IQ2!|L6!-wY#%Cz~f+DdC`1Ze>;4E;5!W53?Pu4|e$IUNG&j`%N0uL*h!VnPkV&yz+3=2TSd z+zy91Ee;*)lkbyfD&*O#n7w1uq6YtP{w@?BCQYQS)VF$&o4&1`N_e9zIP;`QJ7qqx~rM9=1oY9#_-;`Xz-Iw~aHyd*Rt_1BNrF2{jL@4@f_KYGz z;w#Wr4jEL6X4y;#0O$+n9t;)^z=j#NM~!Oto1rKN&YA`o5mql-E;a@YYEx-57UQ5; zl`mT!mntqgc+ks91{zX&o&Ln%=_3^0h|M%)1F3i2oH1>>{+H1i zoc#v(q5AiFy+grAnz{nq+!;OB^Wn=^lTFbn!!;h(HU2&kyvMNIgZn?9e=aal?P?TS zk7AjrXpec>xMDE^kXq42E>%0t|I($Ac#2Dz(MZYa+uD7ZtjhO^2l zLcAP9HaxA{e<`lF!omw;P~S=~+00!T#uT$x=B%=YOO2mM!6<%F+#8^BMo-En!n4oK z-s*k=ODczH+gRL|GJgkJ@->Gl_GkY)>>B`nd>&stbm?=y#kOrEyEPO>KZ*$srm*y+ zRQuIK6Q^@c)!P3~n^OLA^o~lS>wT83E3`Y@$2$9WX4kvYuSX4OK z&prYvv-fw`=SF~O>+-G~bApJFSuka;J<6JuQPIG71fthoTE9EV?tLM5BD3 zlR0I&NP{+=+86?1Se%G!ozY>MqyX=$(?pZxr0>S{l4@eU@5XQBb;Qo7F~44ad(nPx z-Q53@KZbweyJ1{&PuoF&a)LJ1B`6A}F9*8ZLB|r;hsPy;%_94Yt}XOu8LzXvun%Cr976~+N(Ac42rPS>PurkL^;hTbAK)%eE#N7# zPSWfqYq*zQR8M&iJSC3A~KIUI+G4U2GJZS`5fOhzDs;p zq20-2agmd(Y*qh?GSV8K)bj0ZcN78x8uUF0jRvqpEKFzWQ&~}JBuOF|aDb9P)QF{6 zkb&qJX?%P*hTkmIl4p+U710qx`Lag15y}G#UqZ9yew)lyMGX(){#UJpwY(d7)nvTz zRgBK8&NuQrzKVClwLt*SXfV@%qu=?C(4czd*YU zLK=(F?EL}n&9_Fo3y(=DwMj(!`#JJN!T81%ALDnpj+G7{KSI{sg8X{Kr1e_19i+_W zHFV1G0DxPDZzW80&MafTlHLaq3_uI|F|vG1$cZ48v~<~73;>Pw91H<4A`nBvx=h8! zgpU9rWnzU>Gpu6v?z2ZYt<}q#uSG4r@d!c5n77$94kO(XL{8G%nijsEMbhgJq_MpK z--zUoWI#R3$ZVErO@XNB68)vn+`njefZ$g_jZ2}?aMx0P56uleK1yB@7c>|ixO}zZ z`|`S3i~BXf`Fo=p{2^mt4WQ|VUzsy8d2k<%Nzr4Xm^6Tfs0dPrD?ge^>c16n17H;y zI+nX~K^%NUu&LHO#a6_GoI{qhZdd>$`@XQkS{sAH)7oml_cdq6;*J~Qt3Th`=P(K+ z4~I*dr=c6gBW^7MW`Ts6*HdjnPdCO`ONc+@O6vTxPGV-7Y7LeyooajQn2<4eRGK7b zpHdpndQGh>tWXF2Ui$3v?Ai|8j~`taLIqTkout@r#S*^vd9lQOyePxC$!h3P_*TW1 zb7~g2&C`X0DN*fQg>i@9t%vA^^?`T`e0(1AxmFt+WLCr^~=d`osf7c< zh3Yl`XH+PzC<_d>(RkBSgyeth~PRt$PKLUDfeSraY~J#SvyJfY;fcH&?)ok&%UV%L(QePnzU z+2zsu^PjZxxjQjBzOBX2GR0O4n+b&1w<%3({Lqb=Zpz zQw925VV$T)Xqj#&V;a+HL`rm7>$ap0)rO=7aE4~8i57FI(=AewLb5=HoFY$9D(q7u z`P8|pUL)NXeN6#ZBMt*C?!=0Eo+x*31D0(RE~B`l@|Z#}7d$HA5uWRdwDCPcRX#73`2|X5Hsv|51%Y9L-*4>~;kOgSwN2y^iZXBC=&t2vl~0@uh500LvI!~tQ|$JUwh^-~`7 zX7E1Blq92Um{(fK zs9AOS)Vk5CCS#t=F4^Y*(uh71m_j4W4Y@&T00+r|lia{auwW!oB9y@aEKF_$_(c+P zc=paH*nkzT)-o51V?BH*DSC|Aqi4)WcF^Zw?Gs6ZL4kt?+vTAH6pWTM=N7)si-A(k zjzoYn;Uu(!Y)#C`!MdnPnb}3g7Lg7c>}W-oQc5AUCf{3Z{DpfYm2N>q_N*F~D)_>? zP7N8qgpC(j=g~VSiPg_xf5Z|7b4xF(amio$T8_uZUJ$A9n5dGTbRhKL#|`6|5Mq%P zqwZv7y0fWY8n;r$nuHc}UI5@7HFj&19BKWxDzP2#POXq%%m&HMVmyg!ArIJX$ zbvMO+e6z)#Yv-;<9-p&R3Hcvf0YMKiJgPJXhkD$$=c~oSjx9*W^uj;Km>=*+Km2r9 z=>a-i+-6#E8XGV-hzYY!@{s9#GGQtZRFb;Knim)}@g|lRPLId5w;hmH4q*StOov8s z|5jSwx6967(cOT0)y{)%`FnOczs#{ZhZ>Els&iL8)Ml)t(Swl9^0CweYnbRG5s_Pr zInXGK@sLS3PW_0>M}5TR3jl9W29`7)4T%f}RUxX%-XNR@4^YVR6`}B2aH91ur|%m| zMHg0y&&h4MM{0FCyB6h*x~J}0B)%s3w8c*|i<0Jf>wIACc&*-dsfv02SG+#c)dQ7t zC3&5gW$lPl@hnB+gevokIo9ssn4tjCFCLpJ@VPO19w(QYJ^j2X#eb=FZ}V{i{ec28 zA&ipN#e2nnyXnt%GcSYm4R! z(fy2%HeTj>j%Zya_E--Gm(GUOcAt&>_&j~7PsT;6G6J2Ksf`3e5a=$2 z1eu zF)_ioJ{$vNU~_$N5Fyx}4$N%~W`W_ja|FauFrnibeBrk+ngJ&5pSTdF0sB_~EZhvZ zAl%(DN8g;ryIW}$s{dPegy8EG2-TIYS|PRCwRhgYS$v<90_Ay@d;7gY7T{p7brOx) zxqby)!b`C|D`G`!OR64PtvV%(g(*f$EDQgr6xVJ=Plp(;I%)`v)63L zX?^=Uo-FRe@6gX}%k$;!`yZkDPuF_?e!u@9y)F3eYxeXOuw4ZK0HDGg0Ql_VQaUXa zTx1>>zF{1!LAcQ8?3)duLGqBOJs!daH1`OIM`mq=JxDe#dx~Nd7lcL+(>iEOID-M8 zAwi&$0GVTA*vjuH^19oe@RC?JAi$9%$ztP6BeCGy!@(BI60s19TPl}}imM}-=~O$y z*zC%bq4PwgvJrEHw1BvDyd2aAEEp>gB(ni-{-2a-(8W;0!uISP+6lg)n}Jv@AmW^X z&pd7UXfXs-_VViPM-I5JLWb&yf z`>nY$h*i}^Vz6sgcR7jH`-8OV!bkl@{o7AQ5B|9mwP~Zc#d6dxE&;OXwx;Rxvdwt? z)$OTr;V!L=*UzZwJ(>jp9g%eYx*5#tS{rSqZAM;SAAXOC)G66`>M$)Hx@Onqx~K2^ zEVFhBG1gvdTpMim=(V;n)abQ%cz%YS^#hxJOOL?5nfFaw4M`i1!oUCC9z5b+Jy{yA zMIVKFv!?1%0Kfx)SZT+97RH49bhM1wxQ;j>x>=YAEDUk{mTjMe!3I>-Eo-5Yf^4w- zN%M0eI!uF}SUvG@3^rwIAJ&)dT710~EVnP)PpI%&hv%bNxX+{#YAua;6f`*kzh+b& zW6}^x9(A*Y!6*>FUuizH>4^r%`CImV*E@ceW4kr($fM_z2r#Suy48Wc(o}GZaZ7S@ zx?e-M@A0$GW1MwgA^g+f?5CejuUk!jd?P=^Z75cd;b0@!qcVXa z_A*Y=PW@f@bZU(Wws&JB>mJnCOnpven^#^bKZ1nN0(R){8ziZkxwqx5+hph+5oMF? zi_~Qi5P(2rm`Z7&`78^jI1en?(+e<;#-|vL2jiB4y9Srr=n+;O8e`hH8MQyY`{4F# zXp@UKL|xK`$Qsf~rpLw;Y7`EM0AV|nTV4d4=tZA~>^tLS7zFP|UZl&h*2OE`wv*Xx z112c!5~N5iX8vir%s~iwauoV%0W7-Q_Eo*jymL3ova4TX9l8i+@Hu zvD*R4dZ4_V6S7U=QxNvZP_84QXGFTfNnRxE^g!^?#Sw3&cbLjD0ESx`(LC@!h3pBk zr@PE4=UM)(UM_dSALmhqu>>Lf)9s7+2V6XnRmZ{G%zWq zzZcDn{}KcRV*MJSQcB9~3`+ZCkOf_bGm-R|IExryP-7y$4K(8Yd)>z!!<8ztD|nGt zXS;d*-%u*vuzhE@Y=<=HXhR&tsnUiRnB@$Ks4tycQzrbI3U*|A5=?pW?WU$aPbC?#|Es z6JLZ)yzxm%&|xN`>hzMd^gG|za1L~d_1Kx*96c!wAqfB^{< z1AmWHXseH0k041dXRB`eNj+k0q@Ub0TqEuy!AG7TKb04lNz0b__R8 zHorY@_&HQoE&u>U);J=YJKNI77mmxL4w6MbrZ8It7{KHn6l zxdrhvrZESE8~*1de+MA=33cAFh&*`ac3|w~5MFh>wROv7q@-x|c_HuI-mRlsPZbg+ z?fLk=Ni;p=r93hSvsEd-e|Rzb-T1qzkl9beA95Pelsv5yEY(jkv#F-YBq!aRpZ5v@ zA7}vh>%n^ip4|B2NSsUh;1Mj~Eg~pgoQ>rMF)M-;SmL&PBXp5-3b5 z%am~+NmZ3TKUsfC8ne z+49!B=eduF zj;??H=M>k{YtL(v?VA#J+4WL1SzLZ-@lXux9l!#>=KA+sBBAgol~9~>zzRM9{96k@ zf&>a$mPJ)0fCp-v>3#Si$_3LCPk04;1q~9j!5!JfQ{oO z;=t0M*uz1Dm7qw)4vkBo0zk{#at(MSIRr+GD)V`3dEH!18y8(_qBsbJw1%Wxk}w;h ze0!b)&j#u(YdaH`r6baSSturq8}>5Q<|-B%njoPnXi*|V$76RTvo#g($SaEpId$2X zeyi=)TjzzKDAcdHJUn4<@-og31j_`W)~GB$aGT<1{Bm=)w!B2jrx40O(JD zC7hYg!j2h8$?pB@E1VTrK`>;--l4~|%B(kT+>*#O-R0D!RLNP#XVtY8Gm!UvNi(01 z=|!=fNnR+P_p=%LzDmO?`1KdD7_bmUP( zw!9=z{{8@Tu)!*F&)4-IHoRZ^DWAv?VC@2kor#2jivTN8E{O&&ZsCS(4zQ4b%2px) zX(mHM2KJ_={LLOI1`D;x^?s5PFXJ!-i5Hf@qbmatzixM5F}1*hK?pcV784O+5%=g> zHDd8J>TX12WeUFM8x5%vLQ^USucI+f!=auu)ZM(++})S#mFwLP}= zk=l6qs?K25_cNO3?j!nkUdR2_PI(JMxbDz*qp5nL|9<_af9q$=WOwxbaf$Y7iWI|5LreSPqH6djtWK-trYs zU|LazB1ZhCAEoQk2wU6KE?ygN;?NEg88D9UMU?W>o1`A!VvO8F^Wgf7AkmZf|)VTRqrX^lGrSDg}E` z1|2f51w<8lgKkXld zql$EeuItNs!lWD2fPg^8-Hr>V5i%!u^;=sQ_q&Fua+|)VY87eld12>4wY~(ASm`o+ zcINC>OK!~3|F8!@^s7Y1WClR>#&zb<3;ugNxt>cFwQ!$0{a;#wg3Yfrk+`PC#fMO> zR)Gw~FN2eR5aEikEmg}^_)5I$*1ysgTSTkEB1}H$|8-bh-v}7yBmVr}s#^Qk*P~E% z8#W|7L3|{YWjT-Phqi5nR&us&dQN3>RBoZ$;FUCKDb~Xzk3b4DJrF98>wJ?P+jn2q+c>*i$as zXiv>NFC=$gTVAYYW-%p>c=?nF$P4AZoW0rp{d7`m0B+uFupXt9?jAZVuHpXLo!Dqd zpQ;$jWygk{G0vTJo|iYC1~n+j$~|HA5xlUj?IE;xnQxe@Iu0 z-??}E-D1a&2nKN~j=?wX)9^rkkOrV<^=RGJ}vl&NfbdpAcsq?8Fo1OpS` zR9v%b?o7}jfA!+TefG*}U7Th<2d74;>LmJ?qe#~Yx304OLv<6G6#m3&#!L$~DN)}2@1l)0DS>>fpl zf_IQMEk`qe`enP}WN9U2imf}$bybEpb0{k{=n!PUW3-kA0G>H#Px|bbYX~%+jge8J z0F@;%dF8JL5N?s+<-%fr%8FAg-P*wxb{Y;wFpJnKH_ zvGC1nt|tF0m3{;8=3^D=XbBwGxa_?<%33qk8P&L9c40K%5Wn|{)&%Zk_f-W2e>C0b z7n@1*jJwzE`mb=*?Fw`K6X}3Ude;~u#@!ZsWk+dONZvO`p5WjUg8s$eYgCLh13s@hP2NRtYq>cr~ zWR}~bkhj3Jwg8!$1L(vV12jO8@H8!Ph8Aq&Aw;-P?mr>ALqlP-aZPxY#WnUj6o@dG zU&urq5kr9WaDG08Vc3iFobEw)8Ic?Rvu%p7vHksLi;;0 zRh6Ko2r|=KbIi#QR01|PLMlCqQv8l8`LH5}Mm*?}$B&tqB5W-r3CG&v#WoNb3AA}( ztigP}^#MCKCb&cqa|#a^RIcdJro)O?HSUU-@NHhf*z$_xO($*2M!SKl10bk9U+r&| z(327b`ak_v!pRb;ws8opQ@<@AR680ui8c_;$6UWmA-GzY(aE%lzAEupPL0nOMM*2` zli|4To}GeXILbsMHI`sw%EcxtCrR+IMUfuI@!F4wF;um#6o?d`ie~9}8$XgVC4pFL^GqZ#b)O zLJto<{5M4TV;SswW6p~RRf>`|pU5v3t=O=*YK4~>?{6J$`$PaRe8pS})qv@t!$JLI zMlA$HOfFan3AiDECn}H$Kzo)<84{HUH^{LBoTZgVHDm?(RvBnFE}?#dxs`H*%e6GUg9oI2q?(^?!=D^o|t#=?GKiG$!_9Kf`s%H|wz=oyTP z^%E<(?@m@kq`WQIHm#5O(SE^ju|M*pq2VQweypUK(P+*+Yi=l@)sKD+Z&OXfC58R+ zr-q$*A}UAz@oRZUOd1g=#)5N)ZFlhF=5)W_Q0OUMg8c_G6+eP;H>k)qHzx;vRepx%e9%d#-lh%X%pe&fl3HnNs z4@VkDg~g%&1j6E^G$#?Fpv>6=#Hv#iMXV)RIHVcGAY)8QD`4R=C}N8nDP{Aq&4L!dz4IKga4Y?3+}d0`5Y*jA1X*nhedPAu*Nij+v}JEK3!QpVEN zCv7}(Mj{iC(wyV7d3aSwBdJneloER#1kYFubCy|-n$GogEt5HOuyc^ls;|lc?pJi# zN9M>8*CS@_ZdtP>nY$9b#KaR0 z;q5s^T_MqkY_UKVOZ9zmHwd;lgQX2aVVMPkbAT!pv##bWlCpeE3pyfIH>XHlwDP|O z@C<;-zlG;{1_CR}dHUFX1OJQFercsdc6*UUODbE41zk26g#@2gV8S~Kfm0yqK`CRH z6xSQ)cmuPXB8mp=-dVM3_xt%z|5{IV{OuQX0%xQ)%YNbc;zOeQH?}qJ0w-Mz@_}Au zvrEH}0)k6-@=i6L7JIj{_Fv?q!)pfrX;}7KICmFwRqcs{Fw+FOE^6|+Z zqf`SJE);h4VbU#WBo@?d-Gnpeuo0BATKO%-s}dpQn24Fy+JZnb7y=6|ln^3uH&S1L zD~%%Ih8c;+93xNBX`%y$R7&)!^)_9^u|Qf-15v_O8d_G~z1O}ksKeGNJMrRW-6g2_ zsvbkW_~^StB(^~B*GdD-LxuFtZ_q|;rdDl}_wC!SZy&$?x;~-Zv=b1Y>HnNB!XXt5~Cd8w@3K}ImLXzm4XzJK1FQWxHZLTl!vFagqv-8zkl zq&uZ-DD}7ZcNqX7r^C0y^iE6cthMBFUrZoyc=QVlcAPp6Lg+AzdEo@VDi~J&5E-JL z15@hRdsQ^Q6}(~R-~@+&ff@Bh4T0d}DD0l$xbY0~7QG`C7Ei}ZrA`8$7`6abE?$27 zKS(%(5F}@a)I*6lYmIh1D@5FLbD^^7G`Zp}D9TmX#b2FE7{UdCB+3e7agN!+eu-hi z3xeCp(+nrkbfN5%g{^9zjy3uUOPA(nq>GUwoAct7L5Z!5uurdoaF&Aia`|4=c_peb%V)L z*z_qrS}LBcY;YQzS>H-0>{A#r>4oPrX7+5AV|5$9Q%w)=?0NV6U? zXf&%1(c_GU;xP(24=$<4HyH?a4t^FR|3L7uzI#*AlsXit4%cI2DuR!#bS-V@;?>mC zvrf92rJZhfKc#Gfv&Kio>oBlwW8jPl9h&JXQve8sl42zqrA~?(L(m}*8)(*#@aCjs&&1;(q3Wp4=jM;pl4xAfs;ojS z>!D030F+N6Qcts3yxV+oKST59t)K3er$j-;Hoaq;ovkDOG~gvaeZ2j^&ah$BA@;97 zYwapjrH8STVE0FCfnPS%v#fK+;akngyYBZQz<}j0)CFh&fB=w(qv4GFW~6fV&Wnsr zrFt~}go}nPGcnl85{E09JJ?HsrYw;;AdZJdJHS7v&JNZ7gBt+B#sML?1IEa4h~gkW zEHs>fAT&gTPJtw(3R}3MaLg}EMG@f{GP3tGpz|O)oW> zFcL0_1Put#B-`3R8hPT@78S__*Oo?%t@xcn`qtB?+VQr-J2J8JMnIb~3||K=K_!GN zU6GiZ083A#eg-bgMMGXfS>j1kiLn$v=$pEduhvrQ=1&*H-t5$*-~gkqEu5pOWA^38 zt@8vDCR;y5b%$1jzURMHTPc{G^9e9yM$o#Fd|+YAVgF7twB*rl=Ij6afjsR+nf5Dm z^%W|04*+pw@ck>5$oc8Mi4+42dU#m34Ii)9s?h$7XdcZhzULVzk8y#t^j7eGU%RdH z#P_Y7ItZO>eM0TnM3PGh2peMpAi_F^V`?&2(-wks&rUi|rEZn6;|a{c=Rp@jiyVYA zEMC0HH`5R+1b_+)446S3O^gLjc}gB^Krv$8@*!afcRXIN5JsNgtc4D510Iu38-^tD z032ft53r5Qo`926*2mt-U}y|u!TeE&MW9@SyjHfs3o1^@ViG}ubRf4rG6VW_4jlQ; zkQ^FOZv0HodR^9)mgB#C!?dX0XdefZrNH9a#jK4n7Mz3)5N!dc4To!BhT95gz@gTz zeZ7@SKdUI5vQssfjBT!iB*`SWXvScmdLnzoO8L5pD$PjA3QXGwXlMTkNuG($5O&Gs z7^dn^SMEh`fDo3-TfSnFei2CQd1|GKVR-hD0ZipQZ4B0xqrG<6Ib7KMSbnZt+RE2F zlu&soV#-inBBnu0!JBAIqQsGuhccEjc`lJA?o`W418`R= zSym-O81CQ*3M3>1$DtO&JJg`>5z>i>JS7QC&eFghK5C`>0He|N)XqxZ2wi_U*KlT` zWy#nzk;FxYyhPyA8gBsYs@g(3Xf4l++~Gz|1LNhhL1e2JATKaK8ONLj{gquEEsp0D2V0a&ep~MEWo(Knw3OAPu;0YJuDyeoR*X! zSMqxT4+oh13|!%KasqEmo}-)u;0{_@m#f!b+A!#ASu=wNVbuqo1n_Xl^WL4tKjNwI zxGc(-PR<$Bs<%j151m=f#h5;|O|AWAlaE3{(WG)VfVoBY!vvmBemnP&0jn=(=(z9@ z3Ca?RDsC2{b%Q$JK9%CDvOk|`+sQjz(`nYQ;+U7+OqWhpTf_K-2|B&9rVF=^ze@dY z?y?QQFZ;(OCSaO_a*4}{f)2W-PV)oS*U3$5hH%vE$JcZ@FNIo5|uw6v&onqLXFAsL;^|l@N*{mx0WV5fMPXQQ?=Ay z*(;P+H79)r0A&^!n|!aCAxMZ@Ga>PiKP)%)v||)R(#jaJrtyWwloRfg66%9-%$!3q zc(?HeCy^x{E<*|cqTj8zC}^UIrS^&tis3n$;0|O8NH1s-J=`xE2(-5TNQtPh)Z`Ir?aUOml$w5>_pYAM>-NYyniSO03Y=YbkgS))^s>Bp|)o}xv3epkBu>C2e=`sPF+W{H$HK^!e&;%}9g z<`$zG*L-UJTUs+$1sTY@;iE4=8g}-Vl{`v#g~W)=4S+}r=%anxQ~Fi?gZQ^YG7&HX z-HY3RAscrTPES7$j0-X^G>4HqD8cK1tA$55UR`yg-9VHXQT21S2kQ zt6Y≷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�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 Date: Tue, 28 May 2024 01:47:22 +0600 Subject: [PATCH 537/647] 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 538/647] 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 539/647] 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 540/647] 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 541/647] 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 542/647] 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 543/647] 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 544/647] 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 545/647] 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 546/647] 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 547/647] 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 548/647] 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 549/647] 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 550/647] 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 551/647] 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 552/647] 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 553/647] 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 554/647] 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 555/647] 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 556/647] 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 557/647] 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 558/647] 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 559/647] 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 560/647] 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 561/647] 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 562/647] 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 563/647] 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 564/647] 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 565/647] 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 566/647] 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 567/647] 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 568/647] 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 569/647] 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 570/647] 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 571/647] 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 572/647] 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 573/647] 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 574/647] 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 575/647] 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 576/647] 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 577/647] 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 578/647] 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 579/647] 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 580/647] 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 581/647] 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 582/647] 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 583/647] 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 584/647] 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 585/647] 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 586/647] 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 587/647] 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 588/647] 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 589/647] 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 590/647] 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 591/647] 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 592/647] 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 593/647] 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 594/647] 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 595/647] 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 596/647] 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 597/647] 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 598/647] 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 599/647] 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 600/647] 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 601/647] 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 602/647] 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 603/647] 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 604/647] 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 605/647] 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 606/647] 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 607/647] 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 608/647] 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 609/647] 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 610/647] 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 611/647] 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 612/647] 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 613/647] 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 614/647] 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 615/647] 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 616/647] 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 617/647] 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 618/647] 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 619/647] 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 620/647] 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 621/647] 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 622/647] 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 623/647] 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 624/647] 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 625/647] 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 626/647] 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 627/647] 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 628/647] 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 629/647] 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 630/647] 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 631/647] 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 632/647] 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 633/647] 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 634/647] 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 635/647] 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 636/647] 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 637/647] 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 638/647] 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 639/647] 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 640/647] 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 641/647] 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 642/647] 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 643/647] 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 644/647] 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 645/647] 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 646/647] 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 { From fcbe05c898c3e68c6303503fecd933d7950842c7 Mon Sep 17 00:00:00 2001 From: Maksim Mesilov Date: Sat, 8 Feb 2025 01:55:39 +0600 Subject: [PATCH 647/647] EOL --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f41e1b1a..f184775b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ +❗️Bitrix24 forked this repository 🥳 and now I contribute [there](https://github.com/bitrix24/b24phpsdk) +================ + +❗️For new and existing projects please use https://github.com/bitrix24/b24phpsdk +================ + Bitrix24 REST API PHP SDK ================ [![License](https://poser.pugx.org/mesilov/bitrix24-php-sdk/license.svg)](https://packagist.org/packages/mesilov/bitrix24-php-sdk) [![Total Downloads](https://poser.pugx.org/mesilov/bitrix24-php-sdk/downloads.svg)](https://packagist.org/packages/mesilov/bitrix24-php-sdk) @@ -11,7 +17,6 @@ A powerful PHP library for the Bitrix24 REST API |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [![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 @@ -349,4 +354,4 @@ in this project. ## Need custom Bitrix24 application? -Email to mesilov.maxim@gmail.com for private consultations or dedicated support. \ No newline at end of file +Email to mesilov.maxim@gmail.com for private consultations or dedicated support.