Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mdemyanov/a381631a5af6ce626ad290ef51149a5e to your computer and use it in GitHub Desktop.
Save mdemyanov/a381631a5af6ce626ad290ef51149a5e to your computer and use it in GitHub Desktop.
Стандартизация адреса в Naumen & ITSM 365 через сервис Dadata, можно использовать для получения координат адреса

Интеграция Dadata и ITSM 365 (Naumen)

Что умеет

Стандартизация адреса в сервисе Dadata, а также получения геокоординат, которые можно использовать для отображения объекта на карте или в иных целях.

Где использовать

Модуль можно использовать в любых пользовательских сценариях (скриптах) ITSM 365 и Naumen SMP, например:

  1. Действия по событию
  2. Действия в статусах
  3. Скрипты планировщика
  4. И так далее

Как вызывать

Как и с любыми другими скриптовыми модулями, после того, как вы загрузите модуль на своей сервер и добавите параметры подключения. Пример вызова модуля в консоли:

def addresses = cleanAddresses(['Екатеринбург, Ленина 47', 'Екб, татищева 47а'])
return addresses
        .collect { address ->
            "Адрес: ${address.result}, широта: ${address.geoLat}, долгота: ${address.geoLon}"
        }.join('<br/>')

Код вернет модальное окно с перечнем адресов и координат.

Что нужно настроить

Получить реквизиты доступа к Dadata

Просто перейдите на сайт Dadata и создайте учетную запись, затем в настройках личного кабинета получите токен и секретный ключ.

Добавить реквизиты на сервер

Шаг 1 - атрибуты

Создайте в карточке класса "Компания" новые атрибуты:

  1. Адрес подключения (код: cleanerURL)
  2. Токен Dadata (код: cleanerToken)
  3. Секретный ключ Dadata (код: cleanerKey)

Шаг 2 - группа атрибутов

Затем, создайте группу атрибутов "Настройки Dadata) и добавьте туда новые атрибуты.

Шаг 3 - отображение в интерфейсе

Выведите новую группу в интерфейс карточки компании (или на форму добавления), так, чтобы вам было удобно найти ее и отредактировать. На всякий случай, ограничьте доступ к новому контенту только администратору.

Шаг 4 - заполнение данных

Перейдите в интерфейс оператора и заполните данные. Если вы пользуетесь облачной версией Dadata, то "Адрес подключения" заполните как "https://cleaner.dadata.ru". В противном случае, укажите локальный адрес сервера.

/*! UTF8 */
//Автор: mdemyanov
//Дата создания: 27.03.2020
//Код:
//Код модуля: dadataCleaner
//Назначение:
/**
* Методы стандартизации через сервис DADATA
* @method cleanAddress нормализует адрес, а также находит его координаты
* @method cleanAddresses нормализует коллекцию адресов, а также находит их координаты
* Вызывать в скриптах через обращение к модулю: modules.dadataCleaner.cleanAddress('Екатеринбург, Ленина 47')
*/
//Версия: 4.8.*
//Категория:
//Параметры------------------------------------------------------
package ru.naumen.dadata.cleaner
import java.lang.reflect.Type
import groovyx.net.http.HTTPBuilder
import org.apache.http.client.config.RequestConfig
import org.apache.http.impl.client.HttpClients
import static groovyx.net.http.Method.POST
import static groovyx.net.http.ContentType.JSON
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.FieldNamingPolicy
import com.google.gson.reflect.TypeToken
class Constants {
static final Integer DEFAULT_TIMEOUT_IN_MILLISECONDS = 30000
static final String ROOT_HOST_CODE = 'cleanerURL'
static final String ROOT_TOKEN_CODE = 'cleanerToken'
static final String ROOT_SECRET_CODE = 'cleanerKey'
}
class CleanerApi {
HTTPBuilder http
Gson gson
CleanerApi(String host, String token, String secret, Integer timeout) {
http = new HTTPBuilder(host)
http.client = HttpClients.custom().setDefaultRequestConfig(
RequestConfig.custom()
.setConnectionRequestTimeout(timeout)
.setConnectTimeout(timeout)
.setSocketTimeout(timeout)
.build()
).build()
http.setHeaders([
'Authorization': 'Token ' + token,
'X-Secret': secret
])
gson = new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.create()
}
def <T> T post(String path, def data, Type type) {
T serverResponse
http.request(POST, JSON) { req ->
uri.path = path
headers.Accept = JSON
body = data
response.success = { def resp, def reader ->
serverResponse = gson.fromJson(gson.toJson(reader), type)
}
response.failure = { def resp, def reader ->
throw new Exception(reader.inspect())
}
}
return serverResponse
}
}
class Address {
String source
String result
String geoLat
String geoLon
static List<Address> fromString(List<String> sourceAddresses, CleanerApi cleanerApi) {
return cleanerApi.<List<Address>>post(
'/api/v1/clean/address',
sourceAddresses,
new TypeToken<List<Address>>() {}.getType()
)
}
}
//Функции--------------------------------------------------------
/**
* Получить экземпляр api для всзаимодействия с внешним сервисом
* */
CleanerApi getCleanerApi() {
def root = utils.get('root', [:])
return new CleanerApi(
root[Constants.ROOT_HOST_CODE],
root[Constants.ROOT_TOKEN_CODE],
root[Constants.ROOT_SECRET_CODE],
Constants.DEFAULT_TIMEOUT_IN_MILLISECONDS
)
}
/**
* Нормализовать адрес и получить координаты:
* @param sourceAddress строка с исходным адресом
* @result Address объект с параметрами
* - source исходный адрес
* - result нормализованный адрес
* - lat широта
* - lon долгота
* */
Address cleanAddress(String sourceAddress, CleanerApi cleanerApi = cleanerApi) {
return cleanAddresses([sourceAddress], cleanerApi)[0]
}
/**
* Нормализовать адреса и получить их координаты:
* @param sourceAddresses массив строк с исходными адресами
* @result массив Address объектов с параметрами
* - source исходный адрес
* - result нормализованный адрес
* - lat широта
* - lon долгота
* */
List<Address> cleanAddresses(List<String> sourceAddresses, CleanerApi cleanerApi = cleanerApi) {
return Address.fromString(sourceAddresses, cleanerApi)
}
//Блок для проверки работосмособности в консоли> ----------------
return Address.fromString('Екатеринбург, Ленина 47', new CleanerApi(
'https://cleaner.dadata.ru',
'c2ab82ece9b9b6e81be6827eb4a7f849e5f7c2d4',
'5444270950afcdfa89cf08e8c6bd24789b4b32db',
3000
)).result
def addresses = cleanAddresses(['Екатеринбург, Ленина 47', 'Екб, татищева 47а'])
return addresses
.collect { address ->
"Адрес: ${address.result}, широта: ${address.geoLat}, долгота: ${address.geoLon}"
}.join('<br/>')
/*! UTF8 */
//Автор: mdemyanov
//Дата создания: 28.03.2020
//Код:
//Код планировщика: addressCleaner
//Назначение:
/**
* Обновление адресов и координат
*/
//Версия: 4.8.*
//Категория:
//Параметры------------------------------------------------------
def MAX_TO_PROCESS = 300
def FQN = 'ou'
def LAT = 'latitude'
def LON = 'longitude'
def ADDRESS = 'adress'
def BAD_ADDRESSES = ['без адреса']
//Функции--------------------------------------------------------
//Основной блок -------------------------------------------------
api.tx.call {
utils.find(FQN, [(ADDRESS): op.like(BAD_ADDRESSES)]).each { utils.edit(it, [(ADDRESS): null]) }
}
Map objects = utils.find(FQN, [
(ADDRESS): op.isNotNull(),
(LAT) : op.isNull(),
(LON) : op.isNull()
], sp.limit(MAX_TO_PROCESS)).groupBy { it[ADDRESS] }
if (objects.size() == 0) {
return null
}
List addresses = modules.dadataCleaner.cleanAddresses(objects.keySet() as List)
addresses.each { address ->
def updates = objects[address.source]
updates.each { obj ->
utils.edit(obj, [
(ADDRESS): address.result,
(LAT) : address.geoLat,
(LON) : address.geoLon
])
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment