...

Интеграция ELMA365 с 1С

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

  1. v.makarov

    v.makarov New Member

    Система «1С:Предприятие 8» является открытой системой. Она предоставляет возможность для интеграции практически с любыми внешними программами и оборудованием на основе общепризнанных открытых стандартов и протоколов передачи данных.
    С помощью средств платформы «1С:Предприятие 8» можно организовать обмен файлами различных форматов, осуществлять доступ ко всем объектам системы из внешних приложений, поддерживать различные протоколы обмена и стандарты взаимодействия с другими подсистемами (XML, JSON и т. п.), работать с Интернетом и электронной почтой.

    В этой статье мы изучим возможности API ELMA365, рассмотрим функционал инструментария для интеграции ELMA365 со сторонними системами и изучим, какие протоколы и сервисы со стороны 1С помогут организовать обмен данными между системами.

    Платформа «1С:Предприятие 8» поддерживает в прикладных решениях возможность создания web- и HTTP-сервисов и работу с внешними web- и HTTP-сервисами. Так же поддерживается доступ внешних систем к данным приложений 1С по протоколу OData.

    В нашем случае для настройки обмена данными с системой ELMA365 будет использоваться HTTP-сервис и протокол oData. Для POST-запросов из 1С в ELMA365 будем использовать библиотеку ConnectorHTTP.

    Для начала рассмотрим HTTP-сервис. В платформе 1С, в дополнение к автоматическому REST интерфейсу, существует возможность создания собственных произвольных HTTP-сервисов в прикладном решении. Разработчик самостоятельно, с помощью встроенного языка, формирует ответ на запрос. При этом есть удобный доступ к телу, заголовкам и строке исходного запроса, а также есть возможность формировать код, тело и заголовки ответа по своему усмотрению.

    Приступим к созданию нового HTTP-сервиса и напишем функции для Get запроса.

    В ветке “Общие” открываем HTTP-сервисы и создаём новый сервис. В свойстве “Корневой URL” обязательно указываем название сервиса. Это свойство отвечает за формирование URL-адреса к методам сервиса.
    [​IMG]

    Далее создаём шаблон URL (Getcontractors) и методы Get/Post и указываем в обработчике ссылки на функции 1С, которые будут формировать ответ на запрос.
    [​IMG]
    Пример функций для Get и Post запросов будет доступен во вложениях.

    Следующим механизмом для интеграции с внешними системами, который мы рассмотрим, является -
    REST интерфейс. Платформа может автоматически формировать REST интерфейс для всего прикладного решения. После того, как прикладное решение опубликовано на веб-сервере, сторонние системы могут обращаться к нему через REST интерфейс с помощью HTTP запросов. В качестве протокола доступа платформа использует протокол OData версии 3.0. Это открытый веб-протокол для запроса и обновления данных. Он позволяет оперировать данными, используя в качестве запросов HTTP-команды. Получать ответы можно в формате Atom/XML или JSON.

    Для удобства редактирования состава стандартного интерфейса oData воспользуемся внешней обработкой
    “Редактирование состава интерфейса OData”, которая позволит выбрать метаданные для публикации REST интерфейса OData.

    Но прежде чем приступить, для использования http-сервисов и интерфейса OData нам необходимо опубликовать базу, а для этого нам потребуется веб-сервер — Apache 2.2 (или 2.4.) Для публикации на веб-сервере необходимо зайти в меню «Администрирование»->»Публикация на веб-сервере» -> заполняем данные -> "Опубликовать".
    [​IMG]
    [​IMG]

    После публикации на веб-сервере рекомендуется перезапустить Apache, в всплывающем окне нажимаем “Нет” и открываем диспетчер задач, вкладку “Службы”, после чего производим перезапуск службы Apache 2.2. т.к. посредством 1С перезапуск службы Apache не всегда может выполниться корректно.
    [​IMG]

    После публикации на веб-сервер, наша информационная система будет доступна по адресу. Например: http://vm-1c_for_elma.com/1c_for_elma, где:

    • vm-1c_for_elma.com - доменное имя сервера;
    • 1c_for_elma - имя указанное при публикации;
    Закончим настройку состава интерфейса oData. После добавления внешней обработки для редактирования состава интерфейса oData при отладке или открытии через веб нажимаем на “Сервисы” → “Редактирование состава стандартного интерфейса oData” и отмечаем необходимые справочники/документы и регистры, к которым мы будем обращаться через протокол oData.
    [​IMG]

    Обращения через протокол oData производятся по следующему адресу (пример для получения данных справочника Товары в формате json): http://vm-1c_for_elma.com/1c_for_elma/odata/standard.odata/Catalog_Контрагенты?$format=json, где:

    • vm-1c_for_elma.com - доменное имя сервера;
    • 1c_for_elma - имя указанное при публикации;
    • odata/standard.odata/ - обязательная часть, признак обращения к интерфейсу OData;
    • Catalog_Контрагенты - имя ресурса сформированное по правилу;
    • ?$format=json - указывает возвращаемые данные в формате json.
    Полную информацию о правилах доступа и параметрах обращения к ресурсам через oData можно ознакомиться по следующей статье.

    В случае с HTTP-сервисом, например, GET-запрос для получения данных контрагента по ИНН, обращение будет по следующему адресу: http://vm-1c_for_elma.com/1c_for_elma/hs/contractor/0997918926, где:

    • vm-1c_for_elma.com - доменное имя сервера;
    • 1c_for_elma - имя указанное при публикации;
    • hs - обязательный сегмент пути, дающий понять, что работаем мы именно с HTTP-сервисом;
    • contractor - корневой URL http-сервиса;
    • 0997918926 - ИНН нашего контрагента.
    Настройка ELMA365
    Рассмотрим пример обращения при создании элемента приложения "Компания" в ELMA365 через протокол oData для поиска контрагентов со строковой функцией substringof. В данном запросе мы будем получать все компании из справочника 1С “Контрагенты”, где введенная строка будет являться подстрокой “Description” - Наименование.
    [​IMG]
    [​IMG]

    Рассмотрим реализацию данной интеграции. Откроем форму создания. Запишем следующие переменные:
    [​IMG]


    Напишем запрос, выполняющийся на сервере:
    Код:
    
    interface ReqData {
        
    ref_Keystring,
        
    full_namestring,
        
    short_namestring,
        
    innstring,
        
    kppstring
    }

    async function get_companies(): Promise<void> {
        const 
    input_name Context.data.search_string;
        const 
    request await fetch(`http://vm-1c_for_elma.com/1c_for_elma/odata/standard.odata/Catalog_Контрагенты?$filter=substringof('${input_name}', Description) eq true`, {
            
    method'GET',
            
    headers: {
                
    "Authorization": `Basic ${btoa('Login:Password')}`,
                
    "Accept"'application/json'
            
    }
        });
        if (
    request.ok) {
            const 
    req await request.json();
            if (
    req.value.length 0) {
                const 
    dataReqData req.value.map((iany) => {
                    return {
                        
    ref_Keyi['Ref_Key'],
                        
    full_namei['Description'],
                        
    inni['ИНН'],
                        
    kppi['КПП']
                    }
                });
                
    ViewContext.data.data_1c data;
            }
            else {
                
    ViewContext.data.data_1c = [];
            }
        }
        else {
            throw new 
    Error('Ошибка выполнения запроса: ' request.status ' ' request.statusText);
        }
    }
    В данном случае рассматривается Аутентификация 1С:Предприятия. При использовании этого вида аутентификации средствами 1С:Предприятия в конфигураторе для пользователя задается имя пользователя и пароль. Для аутентификации запроса необходимо добавить заголовок Authorization, который будет содержать разделенные двоеточием имя пользователя и пароль в кодировке Base64:
    Код:
    
                    headers: {
                        
    "Authorization": `Basic ${btoa('Login:Password')}`
                    

    Функции, выполняющиеся на стороне клиента:
    Код:
    
    declare const clear_all: Function;
    declare const 
    add_info: Function;


    async function start_prepare(): Promise<void> {
        if (
    Context.data.search_string && Context.data.search_string.length >= 3) {
            if (
    ViewContext.data.get_new_data == true) {
                
    await Server.rpc.get_companies();
                if (
    ViewContext.data.data_1c) {
                    
    clear_all();
                    
    add_info(ViewContext.data.data_1c);
                }
                else {
                    
    clear_all();
                }
            }
        }
        else {
            
    clear_all();
        }
    }


    async function ready_element(element_idstring): Promise<void> {
        
    ViewContext.data.get_new_data false;
        if (
    element_id) {
            const 
    el ViewContext.data.data_1c.find((fany) => f.ref_Key == element_id);
            if (
    el) {
                
    clear_all();
                
    Context.data.full_company_name el.full_name;
                
    Context.data.inn el.inn;
                
    Context.data.kpp el.kpp;
            }
        }
        
    ViewContext.data.get_new_data true;
    }

    Так же создаём на форме создания Виджет “Код” со следующим содержимым:
    Код:
    
    <style>
        
    #help-menu {
            
    displayflex;
            
    flex-directioncolumn;
            
    positionabsolute;
            
    top35px;
            
    max-height50vh;
            
    overflow-yauto;
            
    z-index100;
        }
        .
    menu-element {
          
    background-color#f1f1f1;
          
    min-width160px;
          
    box-shadow0px 8px 16px 0px rgba(0000.2);
          
    z-index100;
        }

        .
    menu-element span {
          
    colorblack;
          
    padding12px 16px;
          
    text-decorationnone;
          
    displayblock;
          
    cursorpointer;
        }

        .
    menu-element span:hover {
          
    background-color#c6c6c6;
        
    }

        .
    dropdown span:hover {
          
    background-color#ddd;
        
    }
    </
    style>

    <
    script>
        $(
    document).ready(function(){
            
    let intervalId setInterval(function() {
                const 
    element = $('#search_string');
                if (
    element.length 0) {
                    const 
    parent element.parent();
                    if (
    parent.length 0) {
                        
    parent.append($('<div id="help-menu"></div>'));
                        
    clearInterval(intervalId);
                    }
                }
            }, 
    500)
        })
        function 
    add_info(all_data) {
            const 
    menu = $('#help-menu');
            if (
    menu.length && all_data.length 0) {
                for (
    let el of all_data) {
                    
    let new_position = $('<div class="menu-element" onclick=<%=Scripts%>.ready_element("' el.ref_Key '")><span class="menu-text">' el.full_name '(' el.inn ')' '</span></div>');
                    
    new_position.attr('data-guid'el.ref_Key);
                    
    menu.append(new_position);
                }
            }
        }
        function 
    clear_all() {
            const 
    all_menu = $('.menu-element');
            if (
    all_menu.length 0) {
                
    all_menu.remove();
            }
        }
        function 
    test() {
            
    alert('click');
        }
    </script>
    Подобные запросы так же можно производить для поиска товаров при формировании Лида.
    [​IMG]


    Теперь перейдём к ситуации, когда необходимо после формирования счета в ELMA365 осуществить его отправку бухгалтеру в 1С.
    [​IMG]
    [​IMG][​IMG]

    Напишем сценарий для бизнес-процесса:
    Код:
    
    async function sendData(): Promise<void> {

            const 
    app await Context.data.outgoinginvoice.fetch();
        const 
    company await app.data.Contractor?.fetch();
        const 
    agreement await app.data.Agreement?.fetch();
        const 
    request await fetch(`http://vm-1c_for_elma.com/1c_for_elma/odata/standard.odata/Catalog_СчетаПокупателям`, {
            
    method'POST',
            
    headers: {
                
    "Authorization": `Basic ${btoa('Login:Password')}`,
                
    "Accept"'application/json'
            
    },
            
    bodyJSON.stringify({
                
    'Ref_Key'app.id,
                
    "Description"app.data.__name,
                
    "Контрагент_Key"company?.data.guid || '',
                
    "ДатаВыставленияСчета"app.data.__createdAt.format(),
                
    "ИтоговаяСумма"app.data.Amount?.asFloat() || 0,
                
    "Договор"agreement?.data.__name || 'Без названия',
                
    "Статус""НеОплачен",
                
    "ОплатаДо"app.data.PaymentDate?.format() || app.data.__createdAt.format()
            }
            )
        });
        if (
    request.ok) {
            
    Context.data.Comment = `Данные по счету ${app.data.__name} успешно отправлены в 1С!`;
        }
        if (!
    request.ok) {
            
    Context.data.Comment = `Ошибка запроса данных: ${request.status} ${request.statusText}`;
        }
    }
    По результатам данного запроса в 1С будет сформирован счёт на оплату в справочнике “Счета покупателям”.
    [​IMG]


    Напоследок рассмотрим ситуацию, когда 1С будет инициировать отправку данных в ELMA365. Например, в 1С приходит платёж по определенному счёту, и его необходимо передать в ELMA365.

    Для написания запроса для отправки данных будем использовать ConnectorHTTP для удобной работы с запросами и ответами в формате JSON.

    Подробнее о данной библиотеке на 1С по ссылке на GitHub.

    Отправка данных так же может настраиваться автоматически, в качестве примера это реализовано через кнопку “Отправить”.
    [​IMG]
    Для выполнения запроса по отправке данных в ELMA365 напишем следующую функцию 1С, выполняемую на сервере.
    Структура JSON и наименование свойств в данном случае определены структурой модуля на стороне ELMA365, который принимает данные значения.

    Код:
    
    &НаСервере
    Процедура ОтправитьПОСТ
    ()

        
    ДокументСсылка Документы.Платеж.НайтиПоНомеру(Объект.Номер);
        
    ГУИД ДокументСсылка.УникальныйИдентификатор();
        
    Объект.ИдентификаторОбъекта ГУИД;

        
    СправочникСсылка Справочники.СчетаПокупателям.НайтиПоКоду(Объект.СчетПокупателю.Код);
        
    ГУИД_Счета СправочникСсылка.УникальныйИдентификатор();
        
    Объект.ИдентификаторСчета ГУИД_Счета;

        
    КомпанияСсылка Справочники.Контрагенты.НайтиПоКоду(Объект.Контрагент.Код);
        
    ГУИД_Компании КомпанияСсылка.УникальныйИдентификатор();
        
    Объект.ИдентификаторКомпании ГУИД_Компании;


        
    СоответствиеДанные Новый Структура;
        
    СоответствиеДанные.Вставить("_totalAmount"Объект.Сумма);
        
    СоответствиеДанные.Вставить("_paymentDate"Формат(Объект.ДатаОплаты"ДФ=yyyy-MM-ddTHH:mm:ss") + ".300Z");
        
    СоответствиеДанные.Вставить("_guid_1c"Объект.ИдентификаторОбъекта);
        
    СоответствиеДанные.Вставить("_guid_account"Объект.ИдентификаторСчета);
        
    СоответствиеДанные.Вставить("_guid_company"Объект.ИдентификаторКомпании);

        
    ИмяСервера "https://elmaserver.elma365.ru";
        
    Токен "55ec3251-ab91-4d36-aab6-e338602d11bd";

        
    СтрокаДанные КоннекторHTTP.ОбъектВJson(СоответствиеДанные);
        
    ДополнительныеПараметры Новый Структура;
        
    ДополнительныеПараметры.Вставить("Заголовки"Новый Соответствие);
        
    ДополнительныеПараметры.Заголовки.Вставить("Authorization""Bearer " Токен);


            
    Ответ КоннекторHTTP.Post(ИмяСервера "/api/extensions/189b0262-78c5-4f14-bf03-30c0635e314d/script/create_payment"СтрокаДанныеДополнительныеПараметры);

        
    Если Ответ.КодСостояния 200 Тогда

            СтрокаОтвет 
    КоннекторHTTP.КакТекст(Ответ);
            
    Соответствие КоннекторHTTP.JsonВОбъект(СтрокаОтвет);

            
    Объект.ИдентификаторЭлемента Соответствие["item"]["app_id"];

        
    Иначе

        КонецЕсли
    ;


    КонецПроцедуры
    В случае, если работа с элементами будет осуществляться через Web API и стандартную функцию “Создать элемент” в ELMA365, то структура будет начинаться со следующего:

    Код:
    
    СоответствиеДанные Новый Структура;
    СоответствиеДанные.Вставить("context"Новый Соответствие);
    СоответствиеДанные.context.Вставить("__name"Объект.Номер);
    СоответствиеДанные.context.Вставить("__directory"Неопределено);
    СоответствиеДанные.context.Вставить("__externalProcessMeta"Неопределено);
    СоответствиеДанные.context.Вставить("__externalId"Неопределено);
    В результате выполнения нашего запроса будет сформирован элемент приложения “Платежи” в ELMA365.
    [​IMG]
     

    Вложения:

    • contractor.txt
      Размер файла:
      5,2 КБ
      Просмотров:
      0
    Последнее редактирование: 8 сен 2022
  2. virff

    virff New Member

    Добрый день, а каким образом мигрировать данные из 1С в ELMA365, имея при этом открытый протокол обмена "odata" что описан в методе