...

Миграция данных из MS Dynamic 365 в ELMA365

Тема в разделе "Примеры решений и дополнительных модулей", создана пользователем ava_var, 4 апр 2022.

  1. ava_var

    ava_var Активный участник

    В этой статье рассмотрим, как мигрировать исторические данные из онлайн MS Dynamics 365. Для решения задачи нужно подготовить обе системы.

    Что делаем в MS Dynamics 365
    Создадим приложение в MS Azure. Получим токены доступа и секретные ключи, чтобы отправлять запрос и получать данные.
    Прежде чем перейти к настройке, прочитайте статью Tutorial: Register an app with Azure AD.
    Итак, выполним следующие действия:
    1. В разделе Azure > Azure Active Directory > Enterprise applications создаем новое приложение.
    [​IMG]

    [​IMG]

    2. Копируем Application ID созданного приложения, это пригодится нам позже.
    [​IMG]

    3. Переходим в раздел Azure portal > App registrations > [App] > Overview. Копируем Directory (tenant) ID.
    [​IMG]

    4. Переходим в раздел Azure portal > App registrations > [App] > Manifest и в параметре allowPublicClient изменяем значение на true.
    [​IMG]

    [​IMG]

    5. Переходим в раздел Azure portal > App registrations > [App] > API permissions. Здесь добавляем разрешения для приложения Dynamics CRM (delegated permissions). Для добавленных прав также добавляем разрешение администратора.
    [​IMG]
    6. Переходим в раздел Azure portal > App registrations > [App] > Certificates & secrets. Добавляем секретный ключ. Обязательно скопируйте значение ключа, т. к. потом это будет невозможно сделать.
    [​IMG]

    Что делаем в ELMA365
    В ELMA365 расширим объектную модель, создадим модуль и напишем скрипты, которые будут вытягивать данные из MS Dynamics, конвертировать их в подходящие типы и сохранять в ELMA365.

    Расширение объектной модели
    Создадим дополнительные свойства для объекта типа Контакт.

    [​IMG]

    [​IMG]

    Создание модуля
    Создадим пользовательский модуль. Про модули можно прочитать в справке по ELMA365.
    Общие данные вынесем в отдельные настройки. Нам нужны следующие настройки модуля:
    [​IMG]

    [​IMG]

    Реализация миграции
    Для реализации миграции используем процесс, т. к. с помощью контекстных переменных можно облегчить создание объектов (экземпляров приложений) в системе.
    Создадим два метода: первый — получение токена доступа, второй — получение данных конкретного типа.

    Первый метод. Запрос токена доступа
    Из справки узнаем, что нужно для получения токена:
    1. Для получения ‘Access token’ используем запрос
      POST ‘https://login.microsoftonline.com/{tenant_id}/oauth2/token’.
      Body(x-www-form-urlencoded) = {
      ‘grant_type’: ‘client_credentials’,
      ‘client_id’: {application_id},
      ‘client_secret’: {secret_id},
      ‘resource’: {dynamic_url}}
    2. Запрос возвращает "access_token".
    3. Срок действия токена ~3600 сек.
    Создадим следующий метод:
    Спойлер: Метод "Запрос токена доступа"
    Код:
    
    // Получить/обновить токен доступа
    // выполнять перед каждым запросом
    async function getAccessToken(): Promise<String> {
        
    // Токен доступа
        
    let tokenstring;
        
    // здесь можно использовать Namespace.cache
        // чтоб не бегать часто на сервер
        // Заполняем данные формы, для отправки запроса
        
    let formdata = new FormData();
        
    formdata.append("grant_type""client_credentials");
        
    formdata.append("client_id", Namespace.params.data.client_id);
        
    formdata.append("client_secret", Namespace.params.data.client_sercet);
        
    formdata.append("resource", Namespace.params.data.resource);
        
    // формируем url с учетом нашего тенанта
        
    let loginUrlstring "https://login.microsoftonline.com/" + Namespace.params.data.tenant_id "/oauth2/token";
        
    // выполняем сам запрос
        // cookie - взяты из документации msdn
        
    let res await fetch(loginUrl, {
            
    method'POST',
            
    headers: {
                
    "Cookie""buid=0.AUcAF83C99FUC0Cv8gF_rcgl3e3XCuMa6s5Mv-6ToLsLpShHAAA.AQABAAEAAAD--DLA3VO7QrddgJg7WevrfYHNCwG6jagKSqAgsluc9sNdzFi4Ol-gZEoNIuUB3j-1P-KZGzPEtOF-gLXFzq-0R2-InPJQoZge_PiupiU70OyxvKMT9QxyrggGm20D-aAgAA; fpc=ApOgUg0uyyBLgqlzJnOcf-bZYZN4AQAAAKKu09kOAAAA; stsservicecookie=estsfd; x-ms-gateway-slice=estsfd",
                
    "Content-Type""application/x-www-form-urlencoded"
            
    },
            
    bodyformdata
        
    });
        
    // в случае успеха - возвращаем полученный токен
        
    if (res.ok) {
            
    let result await res.json();
            
    token result["access_token"];
        };
        return 
    token!;
    }

    Второй метод. Запрос данных (в этом примере получаем контакты)
    Обращаемся к статье Set up a Postman environment и возьмем пример для Postman за основу.
    Спойлер: Пример запроса
    Код:
    
            GET https://{dynamic_url}/api/data/v9.2/{command}
            
    Headers = {
    'OData-MaxVersion''4.0',
    'OData-Version''4.0',
    'Content-Type''application/json',
    'Authorization'"Bearer " + {access_token},
    'Cookie''ReqClientId=ebd37a65-dfc5-4d73-804d-959830622a8a; orgId=868360c2-1d88-493a-947f-31b8a946fce4'
    Примеры команд:
    "/contacts" — список контактов;
    "/accounts" — список компаний;
    "/contacts?$select=fullname,firstname,lastname,middlename,_parentcustomerid_value,emailaddress1,modifiedon" — список определенных параметров контактов.

    Реализация метода получения данных

    Спойлер: Реализация метода получения данных
    Код:
    
    // Основное действие - получить данные
    async function importContacts(): Promise<void> {
        
    // обновляем токен
        
    let token await getAccessToken();
        
    // формируем url на получение данных о контактах и перечисляем необходимые нам поля
        
    let requestUrl = Namespace.params.data.dynamic_api_url "/contacts?$select=fullname,firstname,lastname,middlename,_parentcustomerid_value,emailaddress1,modifiedon";
        
    // выполняем запрос
        
    let res await fetch(requestUrl, {
            
    method'GET',
            
    headers: {
                
    'OData-MaxVersion''4.0',
                
    'OData-Version''4.0',
                
    'Content-Type''application/json',
                
    'Authorization'"Bearer " token,
                
    'Cookie''ReqClientId=ebd37a65-dfc5-4d73-804d-959830622a8a; orgId=868360c2-1d88-493a-947f-31b8a946fce4'
            
    }
        });
        if (
    res.ok) {
            
    let result await res.json();
            
    let contacts result.value;
            
    // перебираем контакты
            
    for (let contact of contacts) {
                
    // Context.fields.contacts ссылается на свойство контекста Контакты (contacts)
                // тот самый лайфхак с легким созданием объекта
                
    let new_contact Context.fields.contacts.app.create();
                
    new_contact.data.external_uid contact["contactid"];
                
    new_contact.data._fullname = {
    firstnamecontact["firstname"],
    lastnamecontact["lastname"],
    middlenamecontact["middlename"]
    } as 
    TFullName;
                
    new_contact.data._email = { emailcontact["emailaddress1"] } as TEmail<EmailType.Work>;
                
    new_contact.data.modified_on contact["modifiedon"];
                
    await new_contact.save();
            }
        }
    }

    Как запускаем процесс
    Процессы из модуля нельзя запускать напрямую, поэтому создадим простое действие БП, которое будет запускать наш процесс. Контекстные переменные не потребуются.
    [​IMG]

    Что получаем

    Получаем модуль, который можно импортировать к себе в систему, настроить доступ к MS Dynamics 365 и выгрузить список контактов в CRM ELMA365.
    [​IMG]

    Обратите внимание: при повторном запуске скрипта данные будут дублироваться.
    Функцию для проверки на дубли можно реализовать самостоятельно в методе importContacts.
    После настройки параметров модуля переходим в раздел Бизнес-процессы и проверяем интеграцию.
    [​IMG]

    Как настроить/адаптировать под себя

    Чтобы адаптировать под себя, выполните следующие действия:
    1. Выберите справочники для миграции, например Компании, Контакты и Сделки.
    2. Придумайте схему конвертации данных: как свойства из Dynamics будут превращаться в свойства в ELMA365.
    3. Подберите команды и набор свойств для переноса. Например, для Компаний(Accounts) запрос может выглядеть так:
    Код:
    
    let requestUrl = Namespace.params.data.dynamic_api_url "/accounts?$select=name,accountcategorycode,customertypecode,address1_postalcode,revenue";
    
    
    4. Реализуйте правила переноса:
    Код:
    
    let new_company Context.fields.companies.app.create();
    new_company.data.external_uid company["entityid"];
    new_company.data.category company["accountcategorycode"];
    new_company.data.client_type company["customertypecode"];
    new_company.data.address company["address1_postalcode"];
    new_company.data.annual_income company["revenue"];
    await new_company.save();
    5. Проверьте на небольшом объеме и сделайте отладку. Затем можно мигрировать все данные.
    Последнее редактирование модератором: 18 янв 2023