Приложения¶
Примечание
Приложения работают в тестовом режиме
Для сторонних сервисов, которым недостаточно API, мы предоставляем возможность создавать приложения (аналогичные приложениям в социальных сетях).
Приложения могут подписываться на потоки событий и добавлять в наш интерфейс собственные виджеты. Потоки дают возможность не делать регулярные запросы на проверку появления новых сущностей и изменения старых, а получать их на указаный url. А виджеты позволяют отображать стороннюю информацию, прямо в интерфейсе Мегаплана, и инициировать действия для сторонних сервисов.
Добавление и управление приложениями происходит на странице /settings/application
.
Аутентификация в API¶
Каждому приложению выделяется токен. Узнать его можно на странице редактирования приложения. UUID приложения и токен можно использовать для аутентификации в API. В этом случае UUID используется в роли AccessId, а токен в роли SecretKey.
Потоки событий¶
Для приложения можно указать список потоков и url, куда они должны отправляться. События приходят на указанный url, в виде HTTPS POST-запросов, с данными в теле запроса. Самоподписанные сертификаты не поддерживаются.
В данный момент, в наличие следующие потоки:
- клиенты (contractors)
- сделки (deals)
- события (events)
- задачи (tasks)
Примерная структура запроса для события обновления сделки:
{
"data": {
"id": "43",
"name": "№1",
"price": {
"value": 188,
"currency": "RUB",
"contentType": "Money"
},
"manager": {
"id": "1000001",
"age": null,
"uid": 1000075,
"name": "User Name",
"avatar": null,
"birthday": null,
"lastName": "Name",
"position": "Директор",
"firstName": "User",
"middleName": "",
"contactInfo": [
{
"type": "email",
"value": "dev-null@megoplan.ru",
"comment": "",
"contentType": "ContactInfo"
},
{
"type": "mobile",
"number": "0000000",
"comment": "",
"areaCode": "910",
"contentType": "Phone",
"countryCode": 7
}
],
"contentType": "Employee"
},
"invoices": [],
"positions": [
{
"id": "85",
"name": "То",
"count": 1,
"contentType": "DealPosition"
},
{
"id": "94",
"name": "Это",
"count": 2,
"contentType": "DealPosition"
}
],
"contractor": {
"id": "1000251",
"type": {
"id": "1",
"name": "Клиент",
"type": "client",
"contentType": "ContractorType"
},
"avatar": null,
"gender": "male",
"status": null,
"company": null,
"birthday": null,
"lastName": "Какой-то",
"position": "",
"firstName": "клиент",
"canSeeFull": true,
"isFavorite": false,
"middleName": "",
"contactInfo": [],
"contentType": "ContractorHuman",
"description": "",
"responsibles": [
{
"id": "1000001",
"age": null,
"uid": 1000075,
"name": "User Name",
"avatar": null,
"birthday": null,
"lastName": "Name",
"position": "Директор",
"firstName": "User",
"middleName": "",
"contactInfo": [
{
"type": "email",
"value": "dev-null@megoplan.ru",
"comment": "",
"contentType": "ContactInfo"
},
{
"type": "mobile",
"number": "0000000",
"comment": "",
"areaCode": "910",
"contentType": "Phone",
"countryCode": 7
}
],
"contentType": "Employee"
}
],
"possibleActions": [
"act_edit",
"message",
"task",
"add_item",
"add_deal"
],
"preferTransport": "",
"unreadNewsCount": 0,
"availableActions": [],
"dateLastReadNews": null
},
"isFavorite": false,
"contentType": "Deal",
"description": "Нам бы того и этого",
"timeCreated": {
"value": "2016-10-24T11:01:03+00:00",
"contentType": "DateTime"
},
"currentState": {
"id": "94",
"name": "Сделка",
"result": "active",
"contentType": "DealState"
},
"positionsCount": 2,
"shortDescription": "Сделка №1 с Какой-то клиент"
},
"uuid": "44b95294-1fcf-4f9f-bd57-a05ab3a68615",
"event": "on_after_update",
"model": "Deal",
"accountId": "mydomain.megaplan.ru",
"fullEventName": "BumsTradeM_Deal.on_after_update",
"integrationUuid": "babf410e-53da-4b52-9be8-efa685bef725"
}
Примечание
Приложение должно быть готово к тому, что ему придет больше 1 запроса, с одним и тем же событием. Для отсеивания дубликатов, в событии присутствует параметр uuid, уникальный для события.
Событие считается успешно доставленным, если запрос уложился в 3 секунды
и http-статус ответа - 200 OK
. Если попытка завершилась неудачей, то следующие попытки будут после паузы: pauseInSeconds = min(2 ^ attemptsCount, 4 * 60 * 60)
.
Событие установки приложения¶
Если приложение устанавливается из каталога, после установки оно получает событие Integration.on_install:
{
"data": {
"name": "Testing",
"uuid": "babf410e-53da-4b52-9be8-efa685bef725",
"token": "YmVmODExOGZlOTZhMzg4YTQ1ZjJmODljMmJkOGU1YmQxYTBkNjM0ODE4NTRlODVhNTAzNzdiN2JjZWI0ZjA5NQ",
"pageUri": "",
"version": 1,
"widgets": [],
"isEnabled": true,
"streamUri": "https:\/\/requestb.in\/sznzpwsz",
"identifier": "testing_foo",
"contentType": "Integration",
"preferencesUri": "",
"subscribedStreams": []
},
"uuid": "bf36262d-d057-4dba-8049-c345e9d321c6",
"event": "on_install",
"model": "Integration",
"accountId": "megaplan.localhost",
"fullEventName": "bums\\integration\\Model\\Integration.on_install",
"integrationUuid": "babf410e-53da-4b52-9be8-efa685bef725"
}
Виджеты¶
Виджеты дают приложению возможность добавить HTML и JS-код в определенное место интерфейса Мегаплана.
Внешний вид окна редактора виджетов:

Загрузка внешнего CSS-файла¶
a9n.css("https://cdn.jsdelivr.net/jquery.suggestions/16.5.2/css/suggestions.css").then(function() {
console.log('CSS loaded');
});
Загрузка внешнего JavaScript-файла¶
a9n.js("https://cdn.jsdelivr.net/jquery.suggestions/16.5.2/js/jquery.suggestions.min.js").then(function() {
console.log('JS loaded');
});
Получение информации о текущем пользователе¶
a9n.user().then(function(current_user) {
console.log('Current user:', current_user);
});
Получение sdk для работы с телефонией¶
mpCallJsSDK представляет собой объект с набором функций и событий для работы с подсистемой телефонии в Мегаплане.
Ниже приведен базовый пример по работе с CallSDK
Документация по Http запросам для телефонии находится
здесь
a9n.callSDK().then(function(mpCallJsSdk){ console.log('CallSDK ready to work'); // получим внутренний номер, или идентификатор, который указан для сотрудника в настройках телефонии var userPhone = mpCallJsSdk.getUserInternalNumberConfig(); // конфиг добавляемый через http api для каждого пользователя var userConfig = mpCallJsSdk.getUserConfig(); // конфиг серверный, создается через http API и для всех пользователей одинаковый var userConfig = mpCallJsSdk.getServerConfig(); mpCallJsSdk.on('connect', function () { // Событие необходимости подключения к серверу телефонии (одно на все вкладки мегаплана) // При закрытии вкладки это событие произойдет в другой одной вкладке // Тут реализовываем подключение(websocket), если это необходимо // когда подключение установлено, нужно сказать об этом Мегаплану: mpCallJsSdk.connected(); }); mpCallJsSdk.on('disconnect', function () { // Событие отключения от телефонии, например при отключении пользователя в настройках // После отключения или при разрыве соедеинения, нужно сказать об этом Мегаплану: mpCallJsSdk.disconnected(); }); // Обработка события нажатия на кнопку звонка в интерфейсе Мегапалана mpCallJsSdk.on('call', function(callInfo){ //Совершаем звонок и далее вызываем функции обработки звонка, описаны ниже }); // При событиях звонка используется структура var callInfo = { fromPhone: '100', // с какого номера звонок toPhone: '101', // на какой номер звонок type: 'in', // in | out providerId: '', // Id системы телефонии для звонка, если есть recordLinks: [''] // Массив ссылок на запись разговора }; // Входящий или исходящий звонок, определяется по callInfo.type mpCallJsSdk.calling(callInfo); //Разговор mpCallJsSdk.talking(callInfo); //Завершенный звонок mpCallJsSdk.finished(callInfo); //После подписки на все события, проставляем возможности текущего приложения в CallSDK, после чего происходит инициализация событий mpCallJsSdk.setCapabilities({ 'HOLD': false, // Hold call 'WEBTALK': false, //Разговор из браузера 'ANSWER': false, // Ответ на звонок 'END_TALK': false, // Завершение вызова 'TRANSFER': false, // Перевод звонка 'AWAY_MODE': false, // Режим недоступен 'CONFERENCE': false, // Конференция ( пока не реализовано ) 'MUTE': false, // При наличии WEBTALK отключение микрофона 'CLEAR_STATE': true, // Сброс состояния (когда нет возможности завершить вызов, но нужно предоставить возможность скрыть виджет телефонии и сбросить его состояние 'VIDEO_CALL': false // Видеозвонок ( пока не реализовано ) }); });
Получение информации о виджете¶
Метод возвражает объект с параметром instance, который является DOM-элементом, в котором находится текст виджета.
console.log(a9n.widget());
Пример виджета¶
В качестве примера виджета, можно рассмотреть отображение подсказок из сервиса DaData , использующее их jQuery-плагин.
<style>
#js-contractor-company-name {
width: 400px;
}
.dadata_container {
width: 390px;
font-size: 12px;
background: #f0f0f0;
padding: 5px;
}
.dadata_container dt,
.dadata_container dd {
padding-bottom: 5px;
}
.dadata_container dt {
font-weight: bold;
}
</style>
<script type="text/javascript">
a9n.css("https://cdn.jsdelivr.net/jquery.suggestions/16.5.2/css/suggestions.css")
a9n.js("https://cdn.jsdelivr.net/jquery.suggestions/16.5.2/js/jquery.suggestions.min.js").then(function () {
var $container = $('<dl class="dadata_container"></dl>').insertAfter("#js-contractor-company-name")
$("#js-contractor-company-name").suggestions({
serviceUrl: "https://suggestions.dadata.ru/suggestions/api/4_1/rs",
token: "<Ваш токен DaData>",
type: "PARTY",
count: 5,
onSelect: function (suggestion) {
var data = suggestion.data;
$container.html('').append($('<dt><strong>' + data.opf.short + ' ' + data.name.full + '</strong></dt>'), $('<dt>Адрес</dt>'), $('<dd>' + data.address.value + '</dd>'), $('<dt>' + data.management.post + '</dt>'), $('<dd>' + data.management.name + '</dd>'), $('<dt>КПП</dt>'), $('<dd>' + data.kpp + '</dd>'), $('<dt>ИНН</dt>'), $('<dd>' + data.inn + '</dd>'), $('<dt>ОГРН</dt>'), $('<dd>' + data.ogrn + '</dd>'), $('<dt>Статус</dt>'), $('<dd>' + data.state.status + '</dd>'));
}
});
});
</script>
Страница приложения¶
Если приложению необходима собственная страница в Мегаплане, доступная каждому пользователю, то при создании приложения, можно указать внешний URL. Тогда по адресу /application/page/<uuid приложения>
, пользователю будет открываться интерфейс Мегаплана, со встроенным iframe.
Как это работает:
- Мы указываем нашему приложению URL собственной страницы.
- Пользователь переходит на страницу приложения (например, по ссылке, добавленной в меню)
/application/page/<uuid приложения>
. - Пользователю показывается страница Мегаплана. В теле страницы находится iframe с адресом
<URL страницы приложеняи>&accountId=<хост аккаунта>&applicationUuid=<uuid приложения>&sessionId=<id сессии>&userSign=<подпись пользователя>
. - Чтобы ваше приложение могло идентифицировать пользователя Мегаплана, оно должно сделать api-запрос по адресу
/BumsSettingsApiV01/Application/checkUserSign.json?uuid=<uuid-приложения>&userSign=<подпись>
. В ответ вы получите либо 403, если подпись не верна или старше 60 секунд, либо данные о пользователе. - Чтобы не делать этот запрос каждый раз, в iframe передается параметр sessionId, который уникален для текущей сессии пользователя.
Пример ответа:
{
"status": {
"code": "ok",
"message": null
},
"data": {
"contentType": "Employee",
"id": "1000001",
"name": "User Name",
"firstName": "User",
"lastName": "Name",
"position": "Директор",
"uid": 1000075,
"birthday": {
"contentType": "DateTime",
"value": "2016-09-06T21:00:00+00:00"
},
"age": null,
"contactInfo": [
{
"contentType": "ContactInfo",
"type": "email",
"value": "dev-null@megoplan.ru"
},
{
"contentType": "Phone",
"areaCode": "910",
"number": "0000000",
"countryCode": 7,
"type": "mobile",
"comment": ""
}
]
...
}
}
Примеры стилей¶
Чтобы ваши виджеты и страницы были похожи на “родной” интерфейс Мегаплана, вы можете использовать нашу подборку стилей
.