Формат EnterpriseData
20.10.2017

Обмен данными с использованием планов обмена и квитирование (на примере)

Внимание! Данный функционал доступен в "Библиотеке стандартных подсистем", начиная с версии 2.3.1.62.

Настройки конфигурации

Для настройки обмена данными с квитированием на стороне конфигурации нужно зарегистрировать стороннее приложение, с которым будет вестись обмен. Конкретный экран этой настройки может выглядеть несколько по-разному в разных прикладных решениях фирмы «1С». В демо-конфигурации, использовавшейся в примерах, он выглядит так:

При регистрации нужно будет указать двухсимвольный уникальный код приложения. Именно он должен использоваться в элементе <From> XML сообщений (в секции <Confirmation>). В элемент <To> надо записать код конфигурации (в нашем примере это «УП»).

Веб-сервис EnterpriseDataExchange

Веб-сервис EnterpriseDataExchange предназначен для двустороннего обмена данными между конфигурацией и сторонними приложениями.

Передача данных из стороннего приложения в информационную базу

Для передачи данных из стороннего приложения в информационную базу последовательность вызовов веб-методов следующая (при наличии правильно составленного XML сообщения):

  1. Проверить соединение с приложением с помощью метода TestConnection.
  2. Отправить заархивированное XML сообщение с помощью метода PutFilePart. Если мы передаем архив одним файлом – второй параметр метода PutFilePart, PartNumber, должен быть равен нулю.  Если архив из нескольких частей – параметр PartNumber должен соответствовать номеру части, начиная с единицы.
  3. После отправки всех частей архива, вызвать метод PutData.
  4. Получить результат выполнения метода PutData можно с помощью метода PutDataActionResult. Обработка полученных данных на стороне конфигурации занимает какое-то время; можно вызывать PutDataActionResult в цикле один раз в, например, 5 секунд, пока он не вернет строку «Completed».
Пример на C#

Реализуем функцию, принимающую параметры:

Функция отправляет данные в конфигурацию и дожидается окончания их обработки на стороне конфигурации.

В составе полноценного приложения по окончании работы функции, если данные успешно обработаны на стороне конфигурации, приложение должно зафиксировать успешный импорт данных в информационную базу и увеличить счетчик исходящих сообщений.

Реализация функции (в виде статического метода):

Копировать в буфер обмена
static void PutData2WebService_ExchangePlan(string serviceURL, string user, string password, string peerCode, string exchangePlanName, string fileName)
{
    EnterpriseDataExchange.EnterpriseDataExchange_1_0_1_1 edDataExchange = new EnterpriseDataExchange.EnterpriseDataExchange_1_0_1_1();
    edDataExchange.Url = serviceURL;
    edDataExchange.Credentials = new System.Net.NetworkCredential(user, password);
    string result = edDataExchange.Ping();
    System.Console.WriteLine("Ping OK");
    string errorMessage;
    bool testConnection = edDataExchange.TestConnection(exchangePlanName, peerCode, out errorMessage);
    if (testConnection)
    {
        //если передано непосредственно имя ZIP-архива - читаем одним куском
        bool singleFile = fileName.EndsWith(".zip", StringComparison.OrdinalIgnoreCase);
        string fileId = Guid.NewGuid().ToString();
        if (singleFile)
        {
            byte[] partData = System.IO.File.ReadAllBytes(fileName);
            //передаем 0 в качестве номера части файла
            result = edDataExchange.PutFilePart(fileId, 0, partData, out errorMessage);
            if (errorMessage != String.Empty)
            {
                System.Console.WriteLine(errorMessage);
                return;
            }
        }
        else
        {
            //счетчик частей файла начинается с единицы
            int partNumber = 1;
            //считаем, что нам передали имя последовательности файлов (*.001, *.002 и т.д.) БЕЗ расширения и точки на конце
            string filePath = fileName + "." + (partNumber).ToString("d3");
            while (System.IO.File.Exists(filePath))
            {
                System.Console.WriteLine("Reading from: " + filePath);
                byte[] partData = System.IO.File.ReadAllBytes(filePath);
                string putFilePartResult = edDataExchange.PutFilePart(fileId, partNumber, partData, out errorMessage);
                if (errorMessage != string.Empty)
                {
                    System.Console.WriteLine("PutFilePart error: " + errorMessage);
                    return;
                }
                filePath = fileName + "." + (++partNumber).ToString("d3");
            }
        }
        string operationId;
        result = edDataExchange.PutData(exchangePlanName, peerCode, fileId, out operationId, out errorMessage);
        if (errorMessage != string.Empty)
        {
            System.Console.WriteLine("PutData error: " + errorMessage);
            return;
        }
               
        string putDataActionResult = edDataExchange.PutDataActionResult(operationId, out errorMessage);
        if (errorMessage != String.Empty)
        {
            System.Console.WriteLine(errorMessage);
            return;
        }
        while (putDataActionResult == "Active")
        {
            //ждем в цикле 5 секунд - ожидаем окончания обработки данных на стороне конфигурации и спрашиваем снова
            putDataActionResult = edDataExchange.PutDataActionResult(operationId, out errorMessage);
            System.Threading.Thread.Sleep(5000);
            System.Console.WriteLine("PutDataActionResult: " + putDataActionResult);
        }
    }
    else
    {
        System.Console.WriteLine("TestConnection fails: " + errorMessage);
    }
}


Вызов метода:

Копировать в буфер обмена
PutData2WebService_ExchangePlan("http://server/1c_app/ws/EnterpriseDataUpload_1_0_1_1", 
                "Administrator",
                "pass@word",
                "ZZ",
                "СинхронизацияДанныхЧерезУниверсальныйФормат",
                "c:\exchange\data.zip");

Пример на Java:

Копировать в буфер обмена
static void putData2WebService_ExchangePlan(String serviceURL, String user, String password, String peerCode, String exchangePlanName, String fileName)
{
 Authenticator.setDefault(new Authenticator() {
  @Override
  protected PasswordAuthentication getPasswordAuthentication() {
   return new PasswordAuthentication(user, password.toCharArray());
  }
 });
 
 URL url = null;
 
 try {
  url = new URL(serviceURL);
 } catch (MalformedURLException e) {
  e.printStackTrace();
 }
 
 EnterpriseDataExchange1011 ss;
 ss = new EnterpriseDataExchange1011(url,
   EnterpriseDataExchange1011.SERVICE);
 
 EnterpriseDataExchange1011PortType port = ss.getEnterpriseDataExchange1011Soap12();
 System.out.println("Invoking ping...");
 port.ping();
 System.out.println("Ping Ok");
 
 Holder<String> outString = new Holder<String>();
 Boolean testConnectionOk =  port.testConnection(exchangePlanName, peerCode, outString);
 if (testConnectionOk)
 {
  //если передано непосредственно имя ZIP-архива - читаем одним куском
  Boolean singleFile = fileName.toLowerCase().endsWith(".zip");
  String fileId = UUID.randomUUID().toString();
  String strResult;
  
  if (singleFile)
  {
   Path path = Paths.get(fileName);
   byte[] data;
   
   try
   {
    data = Files.readAllBytes(path);
   }
   catch (Exception e)
   {
    System.err.println("Exception when open file " + path);
    return;
   }
   
   //передаем 0 в качестве номера части файла
   strResult = port.putFilePart(fileId, 0, data, outString);
   if (!outString.value.isEmpty())
   {
    System.err.println("PutFilePart error: " + outString);
    return;
   }
  }
  else
  {
   //счетчик частей файла начинается с единицы
   int partNumber = 1;
   
   //считаем, что нам передали имя последовательности файлов (*.001, *.002 и т.д.) БЕЗ расширения и точки на конце
   Path filePath = Paths.get(fileName + "." + String.format("%03d", partNumber));
   
   while (Files.exists(filePath))
   {
    System.out.println("reading from " + filePath);
    
    byte[] data;
    
    try
    {
     data = Files.readAllBytes(filePath);
    }
    catch (Exception e)
    {
     System.err.println("Exception when open file " + filePath);
     return;
    }
    
    strResult = port.putFilePart(fileId, partNumber, data, outString);
    if (!outString.value.isEmpty())
    {
     System.err.println("PutFilePart error: " + outString.value);
     return;
    }
    
    filePath = Paths.get(fileName + "." + String.format("%03d", ++partNumber));
   }
  }
  
  Holder<String> operationId = new Holder<String>();
  strResult = port.putData(exchangePlanName, peerCode, fileId, operationId, outString);
  if (!outString.value.isEmpty())
  {
   System.err.println("PutData error: " + outString.value);
   return;
  }
  
  strResult = port.putDataActionResult(operationId.value, outString);
  if (!outString.value.isEmpty())
  {
   System.err.println("putDataActionResult error: " + outString.value);
   return;
  }
  else
  {
   System.out.println("putDataActionResult: " + strResult);
   
   while ("Active".equals(strResult))
   {
    //ждем в цикле 5 секунд - ожидаем окончания обработки данных на стороне конфигурации и спрашиваем снова
    try
    {
     Thread.sleep(1000);
    }
    catch (InterruptedException e)
    {
     //ignore
    }
    
    strResult = port.putDataActionResult(operationId.value, outString);
    
    if (!outString.value.isEmpty())
    {
     System.err.println("putDataActionResult error: " + outString.value);
     return;
    }
    System.out.println("putDataActionResult: " + strResult);
   }
  }
 }
 else
 {
  System.err.println("Connection failed, reason: " + outString.value);
 }
}

Получение данных из информационной базы сторонним приложением

Для получения данных из информационной базы используется следующая последовательность вызова веб-методов:

  1. Проверить соединение с приложением с помощью метода TestConnection.
  2. Выполнить метод PrepareDataForGetting.
  3. С помощью метода PrepareDataActionResult получить результат выполнения метода PrepareDataForGetting. Если в результате выполнения метода PrepareDataActionResult выяснилось, что метод PrepareDataForGetting еще выполняется (в возвращаемом поле «Status» значение «Active»), то выполнение метода PrepareDataActionResult необходимо повторять (например, каждые 5 сек.) до тех пор, пока метод PrepareDataForGetting не будет выполнен (в возвращаемом поле «Status» значение поля станет отлично от «Active»).
  4. Если метод PrepareDataForGetting был выполнен успешно, то получить все части сформированного файла с помощью метода GetDataPart.
  5. Сообщить приложению, что все файлы получены с помощью метода ConfirmGettingFile.
Пример на C#

Реализуем функцию, принимающую параметры:

Функция отправляет данные в конфигурацию и дожидается окончания их обработки на стороне конфигурации.

В составе полноценного приложения по окончании работы функции, если данные успешно обработаны на стороне конфигурации, приложение должно зафиксировать успешный импорт данных в информационную базу и увеличить счетчик исходящих сообщений.

Реализация функции в виде статического метода:

Копировать в буфер обмена
static void GetDataFromWebService_ExchangePlan(string serviceURL, string user, string password, string peerCode, string exchangePlanName, string fileName)
{
    EnterpriseDataExchange.EnterpriseDataExchange_1_0_1_1 edDataExchange = new EnterpriseDataExchange.EnterpriseDataExchange_1_0_1_1();
    edDataExchange.Url = serviceURL;
    edDataExchange.Credentials = new System.Net.NetworkCredential(user, password);
    string result = edDataExchange.Ping();
    string errorMessage;
    bool testConnection = edDataExchange.TestConnection(exchangePlanName, peerCode, out errorMessage);
    if (testConnection)
    {
        string operationId;
        //запросим данные в файлах по 1024Кб (1Мб) каждый
        result = edDataExchange.PrepareDataForGetting(exchangePlanName, peerCode, 1024, out operationId, out errorMessage);
        if (errorMessage != String.Empty)
        {
            System.Console.WriteLine(errorMessage);
            return;
        }
        EnterpriseDataExchange.PrepareDataOperationResult operationResult = edDataExchange.PrepareDataActionResult(operationId, out errorMessage);
               
        if (errorMessage != String.Empty)
        {
            System.Console.WriteLine(errorMessage);
            return;
        }
        while (operationResult.Status == "Active")
        {
            System.Console.WriteLine("Status " + operationResult.Status + ", waiting...");
            System.Threading.Thread.Sleep(5000);
            operationResult = edDataExchange.PrepareDataActionResult(operationId, out errorMessage);
            if (errorMessage != String.Empty)
            {
                System.Console.WriteLine("PrepareDataActionResult out string: " + errorMessage);
                return;
            }
        }
        System.Console.WriteLine("Status: " + operationResult.Status);
               
        int partCount = operationResult.PartCount;
        for (int i = 1; i <= partCount; i++)
       {
            byte[] data = edDataExchange.GetDataPart(operationResult.FileID, i, out errorMessage);
            if (errorMessage != String.Empty)
            {
                System.Console.WriteLine(errorMessage);
                return;
            }
            string fileName2Save = (partCount == 1) ? fileName + ".zip" : fileName + "." + i.ToString("d3");
            System.IO.File.WriteAllBytes(fileName2Save, data);
        }
        result = edDataExchange.ConfirmGettingFile(operationResult.FileID, true, out errorMessage);
        System.Console.WriteLine("GetDataFromWebService completed");
    }
    else
    {
        System.Console.WriteLine(errorMessage);
    }
}

Вызов метода:

Копировать в буфер обмена
GetDataFromWebService_ExchangePlan("http://server/1c_app/ws/EnterpriseDataUpload_1_0_1_1",
"Administrator", "pass@word", "ZZ", "СинхронизацияДанныхЧерезУниверсальныйФормат",
"c:\exchange\data");

Пример на Java:

Копировать в буфер обмена
static void GetDataFromWebService_ExchangePlan(string serviceURL, string user, string password, string peerCode, string exchangePlanName, string fileName)
{
    EnterpriseDataExchange.EnterpriseDataExchange_1_0_1_1 edDataExchange = new EnterpriseDataExchange.EnterpriseDataExchange_1_0_1_1();
    edDataExchange.Url = serviceURL;
    edDataExchange.Credentials = new System.Net.NetworkCredential(user, password);
    string result = edDataExchange.Ping();
    string errorMessage;
    bool testConnection = edDataExchange.TestConnection(exchangePlanName, peerCode, out errorMessage);
    if (testConnection)
    {
        string operationId;
        //запросим данные в файлах по 1024Кб (1Мб) каждый
        result = edDataExchange.PrepareDataForGetting(exchangePlanName, peerCode, 1024, out operationId, out errorMessage);
        if (errorMessage != String.Empty)
        {
            System.Console.WriteLine(errorMessage);
            return;
        }
        EnterpriseDataExchange.PrepareDataOperationResult operationResult = edDataExchange.PrepareDataActionResult(operationId, out errorMessage);
               
        if (errorMessage != String.Empty)
        {
            System.Console.WriteLine(errorMessage);
            return;
        }
        while (operationResult.Status == "Active")
        {
            System.Console.WriteLine("Status " + operationResult.Status + ", waiting...");
            System.Threading.Thread.Sleep(5000);
            operationResult = edDataExchange.PrepareDataActionResult(operationId, out errorMessage);
            if (errorMessage != String.Empty)
            {
                System.Console.WriteLine("PrepareDataActionResult out string: " + errorMessage);
                return;
            }
        }
        System.Console.WriteLine("Status: " + operationResult.Status);
               
        int partCount = operationResult.PartCount;
        for (int i = 1; i <= partCount; i++)
        {
            byte[] data = edDataExchange.GetDataPart(operationResult.FileID, i, out errorMessage);
            if (errorMessage != String.Empty)
            {
                System.Console.WriteLine(errorMessage);
                return;
            }
            string fileName2Save = (partCount == 1) ? fileName + ".zip" : fileName + "." + i.ToString("d3");
            System.IO.File.WriteAllBytes(fileName2Save, data);
        }
        result = edDataExchange.ConfirmGettingFile(operationResult.FileID, true, out errorMessage);
        System.Console.WriteLine("GetDataFromWebService completed");
    }
    else
    {
        System.Console.WriteLine(errorMessage);
    }
}

Ресурсы