Как реализовать последовательное подписание документов электронной подписью в цикле 1С

Программист 1С v8.3 (Управляемые формы) Промышленность, строительство и АПК
← На главную

При разработке интеграций с государственными информационными системами (например, ГИИС ДМДК, Честный Знак или ЕГАИС) программисты часто сталкиваются с необходимостью отправить и подписать сразу пакет документов — поможет модуль интеграции с Честным Знаком и ЭДО. Типичная ошибка новичка — использование обычного цикла Для каждого, внутри которого вызывается стандартный метод БСП ЭлектроннаяПодписьКлиент.Подписать(). В этой статье мы разберем, почему стандартный цикл не работает, и рассмотрим три надежных способа решения проблемы «отложенного» подписания.

Почему стандартный цикл «пролетает» мимо подписания

Проанализируем ситуацию: когда мы вызываем ЭлектроннаяПодписьКлиент.Подписать(), система 1С на управляемых формах использует асинхронную модель. Это означает, что процедура подписания не останавливает выполнение основного кода. Она лишь инициирует процесс, а управление сразу возвращается в исходную процедуру. В результате цикл Для каждого успевает завершиться полностью еще до того, как пользователь увидит первое окно выбора сертификата или криптопровайдер начнет работу.

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

Решение 1: Использование рекурсивного вызова через ОписаниеОповещения

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

Посмотрим на пример кода, который реализует эту логику:


&НаКлиенте
Процедура НачатьПодписаниеПакетов(Команда)
    // Подготавливаем данные, например, массив или таблицу значений
    ИндексТекущейСтроки = 0;
    ВыполнитьПодписаниеОчередногоЭлемента(ИндексТекущейСтроки);
КонецПроцедуры

&НаКлиенте
Процедура ВыполнитьПодписаниеОчередногоЭлемента(Индекс)
    Если Индекс >= Объект.Партии.Количество() Тогда
        Сообщить("Все документы успешно обработаны!");
        Возврат;
    КонецЕсли;

    ТекСтр = Объект.Партии[Индекс];
    
    // Формируем параметры для следующего шага
    ДополнительныеПараметры = Новый Структура;
    ДополнительныеПараметры.Вставить("Индекс", Индекс);
    
    ОбработчикПродолжения = Новый ОписаниеОповещения("ПослеПодписанияЭлемента", ЭтаФорма, ДополнительныеПараметры);
    
    // Вызываем типовой метод БСП
    ОписаниеДанных = СформироватьОписаниеДанных(ТекСтр); // Ваша функция подготовки данных
    ЭлектроннаяПодписьКлиент.Подписать(ОписаниеДанных, ЭтаФорма, ОбработчикПродолжения);
КонецПроцедуры

&НаКлиенте
Процедура ПослеПодписанияЭлемента(Результат, ДополнительныеПараметры) Экспорт
    Если Результат = Неопределено Тогда
        Возврат; // Пользователь отказался или возникла ошибка
    КонецЕсли;

    // Выполняем отправку запроса в гос.систему по текущему элементу
    ВыполнитьЗапросКСервису(Результат);
    
    // Переходим к следующему элементу, вызывая процедуру рекурсивно
    ВыполнитьПодписаниеОчередногоЭлемента(ДополнительныеПараметры.Индекс + 1);
КонецПроцедуры

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

Решение 2: Современный подход Асинх/Ждать (Платформа 8.3.18+)

Если ваша платформа позволяет использовать современные асинхронные вызовы, мы можем значительно упростить код, сохранив привычную структуру цикла. Для этого нам понадобится ключевое слово Ждать. Учитывайте, что начиная с версии 8.3.26, в платформе появились важные нововведения в работе с фоновыми заданиями и асинхронностью, которые полезно знать каждому разработчику.

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


&НаКлиенте
Асинх Процедура СтартПодписанияАсинх(Команда)
    Для каждого ТекСтр Из Объект.Партии Цикл
        Попытка
            ОписаниеДанных = СформироватьОписаниеДанных(ТекСтр);
            
            // Если в вашей версии БСП есть ПодписатьАсинх
            РезультатПодписания = Ждать ЭлектроннаяПодписьКлиент.ПодписатьАсинх(ОписаниеДанных, ЭтаФорма);
            
            Если РезультатПодписания <> Неопределено Тогда
                // Код выполнится только после того, как подпись будет получена
                Ждать ОтправитьДанныеНаСерверАсинх(РезультатПодписания);
            КонецЕсли;
        Исключение
            Сообщить("Ошибка при обработке строки: " + ОписаниеОшибки());
            Прервать;
        КонецПопытки;
    КонецЦикла;
КонецПроцедуры

Важный момент: если в вашей версии библиотеки стандартных подсистем (БСП) еще нет метода ПодписатьАсинх, вы можете создать свою функцию-обертку, которая возвращает Обещание, используя Новый Обещание.

Решение 3: Подписание на сервере (синхронное)

Проанализируем ситуацию, когда нам вообще не нужно участие пользователя в процессе выбора сертификата и ввода пароля. Если сертификат электронной подписи установлен непосредственно на сервере 1С (так называемые «обезличенные» сертификаты юридического лица), мы можем перенести всю логику в серверный контекст.

На сервере все операции криптографии выполняются синхронно. Рассмотрим преимущества этого метода:

  1. Никаких разрывов кода и ОписаниеОповещения.
  2. Высокая скорость обработки больших пакетов данных — для этого есть инструмент пакетного подписания документов для 1С.
  3. Возможность работы в регламентных заданиях без участия человека.

Для реализации этого подхода можно использовать подпись файла методами криптографии напрямую через объект МенеджерКриптографии или серверные методы БСП, такие как ЭлектроннаяПодпись.Подписать(). Помните, что для работы на сервере необходимо настроить права доступа учетной записи, под которой запущен кластер 1С, к закрытому ключу сертификата.

Особенности работы с ГИИС ДМДК: Пакетная отправка

При интеграции с ГИИС ДМДК часто возникают вопросы по методам SendBatch и CheckBatch — есть автоматизация обмена с ГИИС ДМДК и пакетная отправка. Разберем важный нюанс: вместо того чтобы подписывать 40 слитков по отдельности и отправлять 40 запросов, правильнее будет сформировать один XML-пакет, содержащий все партии, и подписать его один раз. Это не только решает проблему асинхронности в цикле, но и существенно снижает нагрузку на сервис и вероятность блокировки по IP за слишком частые запросы.

Если же логика требует именно поштучной отправки, не забывайте о реализации механизма опроса статуса. В актуальных версиях БСП для этого удобно использовать длительные операции, которые позволяют корректно отслеживать состояние процесса. После отправки через SendBatch вы получаете requestId. Вам нужно организовать цикл ожидания ответа, используя асинхронное выполнение длительных операций с помощью фонового задания или ПодключитьОбработчикОжидания с паузой в несколько секунд, прежде чем запрашивать результат через CheckBatch.

Советы по кэшированию пароля

При массовом подписании на клиенте (в цикле или рекурсивно) пользователя может раздражать постоянное всплывающее окно ввода пароля к контейнеру. Чтобы избежать этого, выполните следующие действия:

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

← На главную