Цель - организовать работу внутри процесса так, чтобы при назначении задачи в Elma сотруднику приходило уведомление в Telegram с кнопками задачи. При нажатии одной из кнопок запрос должен уходить обратно в Элму и отрабатывать по сценарию, соответствующему полученным данным.
Для ознакомления была взята статья (https://community.elma365.com/ru/threads/2198/)
В реализации запросов к API Telegram очень полезна дока телеги и особенно: https://core.telegram.org/bots/api#getupdates
Однако в процессе уточнения ТЗ стало ясно, что требуется более узконаправленная реализация - не на модулях системы, с регистрацией веб-хука, а скриптом внутри процесса (подобный способ не описан ни в комьюнити в телеге, ни в темах комьюнити на сайте Элмы).
Разберёмся по шагам:
1. Создаём Telegram-бота с помощью BotFather (https://t.me/BotFather) и копируем сгенерированный токен бота - он пригодится для отправки запросов к API Телеграмма.
2. Создаём необходимый по ТЗ бизнес-процесс. Я для теста работоспособности функционала пустила в параллельный шлюз задачу сотруднику и таймер с последующей проверкой наличия открытых задач у этого сотрудника.
Если до истечения таймера сотрудник в системе отметит задачу как выполненную либо отклонит её, запрос в Телеграмм уже не уйдет - открытых задач нет.
3. Собственно, не имеет большого смысла показывать скрипт поиска открытых задач, как и скрипт их прерывания в процессе, поэтому сразу покажу самое "вкусное" - шаблон скрипта запроса в телегу. На месте переменной ${yourBotToken} должен стоять токен созданного бота, который вам отдал БатяБот. Вместо ${method} функция принимает тип запроса к API. ${userChatId} - id пользователя в тг, которому будут приходить уведомления. Должен определяться динамически, но для теста оставим статику - свой.
HTML:
interface Params {
message_id?:string;
text: string;
callback_data?: string,
reply_markup?: {
inline_keyboard: { text: string;
callback_data: string }[][];
};
}
async function invoke_bot(data: Params, method: string): Promise<void> {
let resp = await
fetch(`https://api.telegram.org/bot${yourBotToken}/${method}?chat_id=${userChatId}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data),
})
.then(async (data) => {
await data.json();
})
}
4. Функция, которую вызываем в блоке Отправка запроса на схеме:
HTML:
async function botInvoke(): Promise<void> {
const method = 'sendMessage';
await invoke_bot({
text: `${fio_str}, у вас есть задача!`,
reply_markup: {
inline_keyboard: [
[{ text: `${Context.data.first_btn}`, callback_data: 'get_task' }],
[{ text: `${Context.data.second_btn}`, callback_data: 'reject_task' }],
]
}
}, method)
}
5. Самой большой сложностью оказалось догадаться, как вытянуть ответ из телеги и обработать callback_data из JSON, поскольку в БП в Элме console.log() не отрабатывает и не видно, в каком виде приходят данные (и приходят ли вообще).
Причиной оказался зарегистрированный ранее веб-хук из модуля, который создавал конфликт.
Не будьте как я - прежде чем писать подобный кейс на скриптах, удаляйте привязанные к боту веб-хуки! )))
HTML:
async function getUpds(): Promise<void> {
let delete_hook = await fetch(
`https://api.telegram.org/bot${yourBotToken}/deleteWebhook`
);
const method = 'getUpdates';
let get_btn_call = await fetch(
`https://api.telegram.org/bot${yourBotToken}/${method}?chat_id=${userChatId}`
);
const updates = await get_btn_call.json();
Context.data.str = updates.toString();
Context.data.upds_len = updates.result.length;
Context.data.upds_call_query = updates.result[updates.result.length - 1].callback_query.data;
const m = 'sendMessage';
if (updates.result.length === 0) {
await invoke_bot({
text: `${fio_str}, у вас есть задача!`,
reply_markup: {
inline_keyboard: [
[{ text: `${Context.data.first_btn}`, callback_data: 'get_task' }],
[{ text: `${Context.data.second_btn}`, callback_data: 'reject_task' }],
]
}
}, m)
} else if (updates.result[updates.result.length - 1].callback_query.data == 'reject_task') {
await invoke_bot({
text: `Задача отклонена`,
callback_data: 'get_finish',
}, m)
await Application.processes._searchTasks()
.where((f, g) => g.and(
g.or(
f.state.like(ProcessTaskState.inProgress),
f.state.like(ProcessInstanceState.wait),
f.state.like(ProcessInstanceState.exec),
),
))
.size(10000)
.all()
.then(async (allTasks: ProcessTaskItem<ProcessContext>[]) => {
const tasks = allTasks.filter(task => task.data.instance?.__id === Context.data.process_id);
await submitTasks(tasks, reason);
})
} else if (updates.result[updates.result.length - 1].callback_query.data == 'get_task') {
await invoke_bot({
text: `Вы выполнили задачу`,
callback_data: 'get_finish',
}, m)
await Application.processes._searchTasks()
.where((f, g) => g.and(
g.or(
f.state.like(ProcessTaskState.inProgress),
f.state.like(ProcessInstanceState.wait),
f.state.like(ProcessInstanceState.exec),
),
))
.size(10000)
.all()
.then(async (allTasks: ProcessTaskItem<ProcessContext>[]) => {
const tasks = allTasks.filter(task => task.data.instance?.__id === Context.data.process_id);
await submitTasks(tasks, reason);
})
}
}
В общем-то, за сим всё. После того, как была выявлена причина, и воскрешён бот, всё прекрасно заработало - при нажатии кнопки задача отмечается как выполненная, и система даёт соответствующий отклик. При нажатии второй кнопки в Элму приходит отказ от задачи.
А дальше можно развлекаться, как вам угодно.