Как передать или завершить дела уволенного сотрудника
Scope:
crm,user_basicКто может выполнять методы: для сценария через вебхук нужны права на чтение и изменение дел CRM. Конфигурируемые дела обновляет только приложение, которое их создало
- user.get — любой пользователь
- crm.activity.list — любой пользователь
- crm.activity.update — пользователь с правом на обновление дела
- crm.activity.todo.updateResponsibleUser — пользователь с правом на редактирование элемента CRM, для которого обновляется дело
- crm.activity.configurable.get — приложение, которое создало конфигурируемое дело
- crm.activity.configurable.update — приложение, которое создало конфигурируемое дело
Выберите инструмент для разработки с AI-агентом:
- используйте Битрикс24 Вайбкод, чтобы создать приложение для Битрикс24 по описанию задачи без знания языков программирования. Агент напишет код и разместит приложение на сервере без ручной настройки хостинга
- используйте MCP-сервер, чтобы разрабатывать интеграцию через REST API в своем проекте. Агент будет обращаться к официальной REST-документации
После увольнения сотрудника его незавершенные дела CRM можно передать другому ответственному или завершить. Для этого нужно найти идентификатор сотрудника, получить дела, где он указан ответственным, и выполнить действие для каждого дела.
Способ обновления зависит от типа дела:
- обычные и системные дела обновляет метод crm.activity.update
- универсальные дела с
PROVIDER_ID: CRM_TODOпередаются методом crm.activity.todo.updateResponsibleUser - конфигурируемые дела с
PROVIDER_ID: CONFIGURABLE_REST_APPобновляются только в OAuth-контексте приложения, которое их создало
Сценарий состоит из четырех шагов.
- Найти уволенного сотрудника и, если дела нужно передать, нового ответственного методом user.get
- Получить незавершенные дела уволенного сотрудника методом crm.activity.list
- Разделить дела по полю
PROVIDER_ID - Передать или завершить обычные, системные и универсальные дела подходящим методом
В результате ответственный изменится у обычных, системных и универсальных дел, которые доступны пользователю вебхука. Если выбран режим завершения, незавершенные обычные, системные и универсальные дела будут закрыты. Дела приложений сценарий сохраняет отдельно и не изменяет через вебхук.
Что нужно до начала
Проверьте условия доступа и подготовьте исходные данные:
- входящий вебхук создан от имени пользователя, который видит дела уволенного сотрудника и может изменять элементы CRM, к которым привязаны эти дела
- в правах вебхука отмечены scope
crmиuser_basic - вы знаете имя, фамилию, e-mail или другой признак уволенного сотрудника
- если дела нужно передать, вы знаете имя, фамилию, e-mail или идентификатор нового ответственного
Вебхук выполняет запросы с правами пользователя, который его создал. Пользователь увидит и изменит только те дела и элементы CRM, к которым у него есть доступ.
Храните путь вебхука в переменной окружения и не публикуйте его в открытом коде.
Дальше в примерах уволенного сотрудника ищем по фамилии Иванов, нового ответственного — по e-mail new.responsible@example.com. В вашем Битрикс24 замените эти значения на свои.
Для серверных JS-примеров с B24Hook нужен Node.js 18, 20, 22 или новее, для новых проектов — 22 или новее. B24JsSDK — ES module: сохраните код в файле .mjs или добавьте "type": "module" в package.json.
1. Находим сотрудников
Метод user.get получает пользователей по фильтру. Чтобы найти уволенного сотрудника, передайте в фильтр ACTIVE: false и дополнительный признак, например фамилию или e-mail. Если дела нужно передать, найдите нового ответственного с фильтром ACTIVE: true.
В ответе сохраните:
IDуволенного сотрудника — передадим в фильтр делRESPONSIBLE_IDIDнового ответственного — передадим в методы изменения ответственного, если дело нужно не закрыть, а передать другому пользователю
Как использовать примеры в документации
import { B24Hook } from '@bitrix24/b24jssdk'
const $b24 = B24Hook.fromWebhookUrl(process.env.B24_HOOK)
// B24_HOOK = 'https://your-domain.bitrix24.ru/rest/USER_ID/TOKEN/'
const action = 'transfer'
async function callMethod(method, params, requestId) {
const response = await $b24.actions.v2.call.make({
method,
params,
requestId
})
if (!response.isSuccess) {
throw new Error(response.getErrorMessages().join('; '))
}
return response.getData().result
}
async function findOneUser(filter, requestId) {
const result = await callMethod(
'user.get',
{
FILTER: filter,
SELECT: ['ID', 'ACTIVE', 'NAME', 'LAST_NAME', 'EMAIL']
},
requestId
)
if (!Array.isArray(result) || result.length !== 1) {
throw new Error(`Ожидался один пользователь, получено: ${Array.isArray(result) ? result.length : 0}`)
}
return result[0]
}
const firedUser = await findOneUser(
{
ACTIVE: false,
LAST_NAME: 'Иванов'
},
'user-get-fired'
)
const newResponsible = action === 'transfer'
? await findOneUser(
{
ACTIVE: true,
EMAIL: 'new.responsible@example.com'
},
'user-get-new-responsible'
)
: null
<?php
require_once 'vendor/autoload.php';
use Bitrix24\SDK\Services\ServiceBuilderFactory;
use Psr\Log\NullLogger;
use Symfony\Component\EventDispatcher\EventDispatcher;
$serviceBuilder = (new ServiceBuilderFactory(new EventDispatcher(), new NullLogger()))
->initFromWebhook(getenv('B24_HOOK'));
// B24_HOOK = 'https://your-domain.bitrix24.ru/rest/USER_ID/TOKEN/'
$action = 'transfer';
function callMethod($serviceBuilder, string $method, array $params)
{
return $serviceBuilder
->core
->call($method, $params)
->getResponseData()
->getResult();
}
function findOneUser($serviceBuilder, array $filter): array
{
$result = callMethod(
$serviceBuilder,
'user.get',
[
'FILTER' => $filter,
'SELECT' => ['ID', 'ACTIVE', 'NAME', 'LAST_NAME', 'EMAIL'],
]
);
if (count($result) !== 1) {
throw new RuntimeException('Ожидался один пользователь, получено: ' . count($result));
}
return $result[0];
}
$firedUser = findOneUser(
$serviceBuilder,
[
'ACTIVE' => false,
'LAST_NAME' => 'Иванов',
]
);
$newResponsible = $action === 'transfer'
? findOneUser(
$serviceBuilder,
[
'ACTIVE' => true,
'EMAIL' => 'new.responsible@example.com',
]
)
: null;
from b24pysdk import BitrixWebhook, Client
action = "transfer"
token = BitrixWebhook(
domain="your-domain.bitrix24.com",
webhook_token="user_id/webhook_key",
)
client = Client(token)
def call_method(method, params):
# Вызов через ядро SDK: в сценарии есть методы без типизированной обертки
payload = token.call_method(method, params)
if "error" in payload:
raise RuntimeError(f"{payload['error']}: {payload.get('error_description', '')}")
return payload["result"]
def find_one_user(filter):
result = call_method(
"user.get",
{
"FILTER": filter,
"SELECT": ["ID", "ACTIVE", "NAME", "LAST_NAME", "EMAIL"],
},
)
if len(result) != 1:
raise RuntimeError(f"Ожидался один пользователь, получено: {len(result)}")
return result[0]
fired_user = find_one_user(
{
"ACTIVE": False,
"LAST_NAME": "Иванов",
}
)
new_responsible = (
find_one_user(
{
"ACTIVE": True,
"EMAIL": "new.responsible@example.com",
}
)
if action == "transfer"
else None
)
Сокращенный ответ для уволенного сотрудника:
{
"result": [
{
"ID": "37",
"ACTIVE": false,
"NAME": "Иван",
"LAST_NAME": "Иванов",
"EMAIL": "i.ivanov@example.com"
}
],
"total": 1
}
Сокращенный ответ для нового ответственного:
{
"result": [
{
"ID": "547",
"ACTIVE": true,
"NAME": "Мария",
"LAST_NAME": "Петрова",
"EMAIL": "new.responsible@example.com"
}
],
"total": 1
}
В результате получили ID уволенного сотрудника 37 и ID нового ответственного 547. Эти значения нужны на следующих шагах.
2. Получаем дела уволенного сотрудника
Метод crm.activity.list получает дела с постраничной навигацией. В фильтре передайте:
RESPONSIBLE_ID— идентификатор уволенного сотрудникаCOMPLETED: N— только незавершенные дела
Чтобы получить только универсальные дела, добавьте в фильтр PROVIDER_ID: CRM_TODO. Для всех дел уволенного сотрудника оставьте фильтр без PROVIDER_ID и разделяйте записи в коде.
В select добавьте поля, которые нужны для выбора метода обновления:
ID— идентификатор делаOWNER_TYPE_ID— идентификатор типа объекта CRM, к которому привязано делоOWNER_ID— идентификатор элемента CRM, к которому привязано делоPROVIDER_ID— идентификатор провайдера дела, по нему разделим дела на универсальные, конфигурируемые дела приложений, обычные и системныеPROVIDER_TYPE_ID— идентификатор типа провайдераSUBJECT— название дела, нужно для проверки результатаCOMPLETED— признак завершения делаRESPONSIBLE_ID— идентификатор ответственного
async function getEmployeeActivities(employeeId) {
const activities = []
let start = 0
while (true) {
const page = await callMethod(
'crm.activity.list',
{
order: { ID: 'asc' },
filter: {
RESPONSIBLE_ID: Number(employeeId),
COMPLETED: 'N'
},
select: [
'ID',
'OWNER_TYPE_ID',
'OWNER_ID',
'PROVIDER_ID',
'PROVIDER_TYPE_ID',
'SUBJECT',
'COMPLETED',
'RESPONSIBLE_ID'
],
start
},
`crm-activity-list-${start}`
)
activities.push(...page)
if (page.length < 50) {
break
}
start += 50
}
return activities
}
const activities = await getEmployeeActivities(firedUser.ID)
function getEmployeeActivities($serviceBuilder, int $employeeId): array
{
$activities = [];
$start = 0;
do {
$page = callMethod(
$serviceBuilder,
'crm.activity.list',
[
'order' => ['ID' => 'asc'],
'filter' => [
'RESPONSIBLE_ID' => $employeeId,
'COMPLETED' => 'N',
],
'select' => [
'ID',
'OWNER_TYPE_ID',
'OWNER_ID',
'PROVIDER_ID',
'PROVIDER_TYPE_ID',
'SUBJECT',
'COMPLETED',
'RESPONSIBLE_ID',
],
'start' => $start,
]
);
$activities = array_merge($activities, $page);
$start += 50;
} while (count($page) === 50);
return $activities;
}
$activities = getEmployeeActivities($serviceBuilder, (int)$firedUser['ID']);
def get_employee_activities(employee_id):
activities = []
start = 0
while True:
page = call_method(
"crm.activity.list",
{
"order": {"ID": "asc"},
"filter": {
"RESPONSIBLE_ID": int(employee_id),
"COMPLETED": "N",
},
"select": [
"ID",
"OWNER_TYPE_ID",
"OWNER_ID",
"PROVIDER_ID",
"PROVIDER_TYPE_ID",
"SUBJECT",
"COMPLETED",
"RESPONSIBLE_ID",
],
"start": start,
},
)
activities.extend(page)
if len(page) < 50:
break
start += 50
return activities
activities = get_employee_activities(fired_user["ID"])
Сокращенный ответ:
{
"result": [
{
"ID": "1501",
"OWNER_TYPE_ID": "2",
"OWNER_ID": "18",
"PROVIDER_ID": "CRM_TODO",
"PROVIDER_TYPE_ID": "TODO",
"SUBJECT": "Связаться с клиентом",
"COMPLETED": "N",
"RESPONSIBLE_ID": "37"
}
],
"total": 1
}
В ответе метод возвращает массив дел. Для следующих шагов нужны поля ID, OWNER_TYPE_ID, OWNER_ID, PROVIDER_ID и PROVIDER_TYPE_ID. Если метод вернул 50 дел, запросите следующую страницу с start: 50.
3. Разделяем дела по типу
Поле PROVIDER_ID показывает, каким методом нужно обновлять дело. Разделите массив из шага 2 на группы:
CRM_TODO— универсальные делаCONFIGURABLE_REST_APP— конфигурируемые дела приложений, в примере сохраняем их в отдельный список без изменения- остальные значения — обычные и системные дела
function splitActivitiesByProvider(activities) {
return activities.reduce(
(groups, activity) => {
if (activity.PROVIDER_ID === 'CRM_TODO') {
groups.todos.push(activity)
} else if (activity.PROVIDER_ID === 'CONFIGURABLE_REST_APP') {
groups.configurable.push(activity)
} else {
groups.base.push(activity)
}
return groups
},
{
todos: [],
configurable: [],
base: []
}
)
}
const groupedActivities = splitActivitiesByProvider(activities)
function splitActivitiesByProvider(array $activities): array
{
$groups = [
'todos' => [],
'configurable' => [],
'base' => [],
];
foreach ($activities as $activity) {
if (($activity['PROVIDER_ID'] ?? '') === 'CRM_TODO') {
$groups['todos'][] = $activity;
} elseif (($activity['PROVIDER_ID'] ?? '') === 'CONFIGURABLE_REST_APP') {
$groups['configurable'][] = $activity;
} else {
$groups['base'][] = $activity;
}
}
return $groups;
}
$groupedActivities = splitActivitiesByProvider($activities);
def split_activities_by_provider(activities):
groups = {
"todos": [],
"configurable": [],
"base": [],
}
for activity in activities:
provider_id = activity.get("PROVIDER_ID", "")
if provider_id == "CRM_TODO":
groups["todos"].append(activity)
elif provider_id == "CONFIGURABLE_REST_APP":
groups["configurable"].append(activity)
else:
groups["base"].append(activity)
return groups
grouped_activities = split_activities_by_provider(activities)
После разделения в коде есть три локальных массива: base, todos и configurable. Эти массивы не являются полями ответа Битрикс24, они нужны только для выбора следующего метода.
Если в списке есть дела приложения
Дела из массива configurable не передавайте в методы обновления этого сценария. Входящий вебхук не может обновить дела с PROVIDER_ID: CONFIGURABLE_REST_APP, потому что такие дела изменяет только приложение, которое их создало.
Сохраните эти дела отдельно:
const skippedConfigurableActivities = groupedActivities.configurable
$skippedConfigurableActivities = $groupedActivities['configurable'];
skipped_configurable_activities = grouped_activities["configurable"]
Если нужно передать такие дела, выполните это в приложении, которое создало дела:
- Авторизуйте запросы в OAuth-контексте приложения
- Получите дело методом crm.activity.configurable.get
- Передайте в crm.activity.configurable.update текущий
layoutи новое значениеfields.responsibleId
Если вызвать методы конфигурируемых дел не из приложения, Битрикс24 вернет ошибку ERROR_WRONG_CONTEXT. Если приложение не создавало дело, Битрикс24 вернет ошибку ERROR_WRONG_APPLICATION.
4. Передаем или завершаем дела
Выберите режим обработки перед запуском обновления:
transfer— передать дела новому ответственномуcomplete— завершить незавершенные дела
Обычные и системные дела обновляйте методом crm.activity.update. Развитие метода остановлено, но в документации не указана актуальная замена для изменения RESPONSIBLE_ID у обычных и системных дел.
В режиме complete этим же методом закрывайте универсальные дела. У методов crm.activity.todo.* нет отдельного метода завершения дела. Чтобы передать дело, отправьте поле RESPONSIBLE_ID. Чтобы завершить дело, отправьте поле COMPLETED: Y.
async function updateBaseActivities(activities, action, newResponsibleId) {
const updated = []
for (const activity of activities) {
const fields = action === 'transfer'
? { RESPONSIBLE_ID: Number(newResponsibleId) }
: { COMPLETED: 'Y' }
const result = await callMethod(
'crm.activity.update',
{
id: Number(activity.ID),
fields
},
`crm-activity-update-${activity.ID}`
)
updated.push({
id: activity.ID,
method: 'crm.activity.update',
result
})
}
return updated
}
const activitiesForBaseUpdate = action === 'complete'
? [...groupedActivities.base, ...groupedActivities.todos]
: groupedActivities.base
const updatedBaseActivities = await updateBaseActivities(
activitiesForBaseUpdate,
action,
action === 'transfer' ? newResponsible.ID : 0
)
function updateBaseActivities($serviceBuilder, array $activities, string $action, int $newResponsibleId): array
{
$updated = [];
foreach ($activities as $activity) {
$fields = $action === 'transfer'
? ['RESPONSIBLE_ID' => $newResponsibleId]
: ['COMPLETED' => 'Y'];
$result = callMethod(
$serviceBuilder,
'crm.activity.update',
[
'id' => (int)$activity['ID'],
'fields' => $fields,
]
);
$updated[] = [
'id' => $activity['ID'],
'method' => 'crm.activity.update',
'result' => $result,
];
}
return $updated;
}
$activitiesForBaseUpdate = $action === 'complete'
? array_merge($groupedActivities['base'], $groupedActivities['todos'])
: $groupedActivities['base'];
$updatedBaseActivities = updateBaseActivities(
$serviceBuilder,
$activitiesForBaseUpdate,
$action,
$newResponsible !== null ? (int)$newResponsible['ID'] : 0
);
def update_base_activities(activities, action, new_responsible_id):
updated = []
for activity in activities:
fields = (
{"RESPONSIBLE_ID": int(new_responsible_id)}
if action == "transfer"
else {"COMPLETED": "Y"}
)
result = call_method(
"crm.activity.update",
{
"id": int(activity["ID"]),
"fields": fields,
},
)
updated.append(
{
"id": activity["ID"],
"method": "crm.activity.update",
"result": result,
}
)
return updated
activities_for_base_update = (
grouped_activities["base"] + grouped_activities["todos"]
if action == "complete"
else grouped_activities["base"]
)
updated_base_activities = update_base_activities(
activities_for_base_update,
action,
new_responsible["ID"] if action == "transfer" else 0,
)
Универсальные дела передавайте методом crm.activity.todo.updateResponsibleUser. Метод меняет только ответственного, поэтому вызывайте его в режиме transfer. В режиме complete универсальные дела уже попали в массив для crm.activity.update.
async function transferTodoActivities(activities, newResponsibleId) {
const updated = []
for (const activity of activities) {
const result = await callMethod(
'crm.activity.todo.updateResponsibleUser',
{
id: Number(activity.ID),
ownerTypeId: Number(activity.OWNER_TYPE_ID),
ownerId: Number(activity.OWNER_ID),
responsibleId: Number(newResponsibleId)
},
`crm-activity-todo-update-responsible-${activity.ID}`
)
updated.push({
id: activity.ID,
method: 'crm.activity.todo.updateResponsibleUser',
result
})
}
return updated
}
const updatedTodoActivities = action === 'transfer'
? await transferTodoActivities(groupedActivities.todos, newResponsible.ID)
: []
function transferTodoActivities($serviceBuilder, array $activities, int $newResponsibleId): array
{
$updated = [];
foreach ($activities as $activity) {
$result = callMethod(
$serviceBuilder,
'crm.activity.todo.updateResponsibleUser',
[
'id' => (int)$activity['ID'],
'ownerTypeId' => (int)$activity['OWNER_TYPE_ID'],
'ownerId' => (int)$activity['OWNER_ID'],
'responsibleId' => $newResponsibleId,
]
);
$updated[] = [
'id' => $activity['ID'],
'method' => 'crm.activity.todo.updateResponsibleUser',
'result' => $result,
];
}
return $updated;
}
$updatedTodoActivities = $action === 'transfer'
? transferTodoActivities($serviceBuilder, $groupedActivities['todos'], (int)$newResponsible['ID'])
: [];
def transfer_todo_activities(activities, new_responsible_id):
updated = []
for activity in activities:
result = call_method(
"crm.activity.todo.updateResponsibleUser",
{
"id": int(activity["ID"]),
"ownerTypeId": int(activity["OWNER_TYPE_ID"]),
"ownerId": int(activity["OWNER_ID"]),
"responsibleId": int(new_responsible_id),
},
)
updated.append(
{
"id": activity["ID"],
"method": "crm.activity.todo.updateResponsibleUser",
"result": result,
}
)
return updated
updated_todo_activities = (
transfer_todo_activities(grouped_activities["todos"], new_responsible["ID"])
if action == "transfer"
else []
)
Сокращенный успешный ответ crm.activity.update:
{
"result": true
}
Сокращенный успешный ответ crm.activity.todo.updateResponsibleUser:
{
"result": {
"id": 1501
}
}
В примере код сохраняет результаты обновления в локальные массивы updatedBaseActivities и updatedTodoActivities. Это не поля ответа Битрикс24, а данные для проверки результата.
Дела из группы configurable сохраняются в локальный массив skippedConfigurableActivities.
Если выбран режим complete, массив updatedTodoActivities будет пустым. Универсальные дела в этом режиме обновляет crm.activity.update, поэтому их результаты попадут в updatedBaseActivities.
Проверим результат
Проверьте результат повторным вызовом crm.activity.list. Для передачи выберите дела по RESPONSIBLE_ID нового ответственного и идентификаторам обновленных дел. Для завершения выберите дела по COMPLETED: Y.
const updatedActivityIds = [
...updatedBaseActivities,
...updatedTodoActivities
].map((activity) => activity.id)
if (updatedActivityIds.length > 0) {
const checkResult = await callMethod(
'crm.activity.list',
{
filter: {
'@ID': updatedActivityIds,
...(action === 'transfer'
? { RESPONSIBLE_ID: Number(newResponsible.ID) }
: { COMPLETED: 'Y' })
},
select: ['ID', 'SUBJECT', 'COMPLETED', 'RESPONSIBLE_ID', 'PROVIDER_ID']
},
'crm-activity-list-check'
)
console.table(checkResult)
}
$updatedActivityIds = array_map(
static fn(array $activity): string => (string)$activity['id'],
array_merge($updatedBaseActivities, $updatedTodoActivities)
);
if (!empty($updatedActivityIds)) {
$filter = [
'@ID' => $updatedActivityIds,
];
if ($action === 'transfer') {
$filter['RESPONSIBLE_ID'] = (int)$newResponsible['ID'];
} else {
$filter['COMPLETED'] = 'Y';
}
$checkResult = callMethod(
$serviceBuilder,
'crm.activity.list',
[
'filter' => $filter,
'select' => ['ID', 'SUBJECT', 'COMPLETED', 'RESPONSIBLE_ID', 'PROVIDER_ID'],
]
);
print_r($checkResult);
}
updated_activity_ids = [
activity["id"]
for activity in (
updated_base_activities
+ updated_todo_activities
)
]
if updated_activity_ids:
filter_params = {
"@ID": updated_activity_ids,
}
if action == "transfer":
filter_params["RESPONSIBLE_ID"] = int(new_responsible["ID"])
else:
filter_params["COMPLETED"] = "Y"
check_result = call_method(
"crm.activity.list",
{
"filter": filter_params,
"select": ["ID", "SUBJECT", "COMPLETED", "RESPONSIBLE_ID", "PROVIDER_ID"],
},
)
print(check_result)
Сценарий выполнен, если количество дел в проверочном ответе совпадает с количеством обновленных дел.
Что проверить в ответах:
- при передаче поле
RESPONSIBLE_IDравноIDнового ответственного - при завершении поле
COMPLETEDравноY - дела из группы
configurableпопали вskippedConfigurableActivitiesи остались без изменений - универсальные дела в режиме
completeпопали в массивupdatedBaseActivities
В интерфейсе CRM переданные дела появятся у нового ответственного, а завершенные дела перестанут отображаться как открытые.
Ошибки и диагностика
Если метод вернул ошибку, проверьте данные запроса.
|
Код или текст ошибки |
Причина и действие |
|
|
Вебхук или приложение не имеет нужного scope. Для дел CRM нужен scope |
|
|
Пользователь, создавший вебхук, не имеет права изменить дело или элемент CRM, к которому оно привязано |
|
|
Дело не найдено. Проверьте |
|
|
Элемент CRM, к которому привязано дело, не найден. Проверьте |
|
|
Ответственного нельзя изменить в закрытом универсальном деле. Получайте только незавершенные дела с фильтром |
Если список дел пустой, проверьте:
- уволенный сотрудник найден методом user.get, а его
IDпередан вRESPONSIBLE_ID - пользователь, создавший вебхук, видит дела уволенного сотрудника
- в фильтре crm.activity.list не указаны лишние условия
- у уволенного сотрудника есть незавершенные дела CRM
Если часть дел уже обновлена, повторный запуск сценария начните со шага 2. Метод crm.activity.list больше не вернет переданные дела по фильтру RESPONSIBLE_ID уволенного сотрудника, а завершенные дела — по фильтру COMPLETED: N.
Что важно учитывать
Перед запуском сценария учитывайте ограничения методов и прав доступа.
- crm.activity.list возвращает дела страницами по 50 элементов. Чтобы получить все дела, перебирайте
start:0,50,100 - crm.activity.update и crm.activity.todo.updateResponsibleUser обновляют одно дело за вызов
- crm.activity.update нужен для обычных и системных дел, а также для завершения универсальных дел. У методов
crm.activity.todo.*нет отдельного метода завершения дела - Универсальные дела определяются по
PROVIDER_ID: CRM_TODO. Конфигурируемые дела сPROVIDER_ID: CONFIGURABLE_REST_APPне обновляются через вебхук, их передают в OAuth-контексте приложения, которое их создало - Если по фильтру user.get найдено несколько сотрудников, уточните фильтр: добавьте
EMAIL,IDили другой точный признак