Как сделать, чтобы обмен данными в 1С не останавливался из-за ошибки в одном документе?

Программист IT и автоматизация бизнеса
← На главную

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

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

Решение 1: Использование конструкции "Попытка-Исключение"

Самый прямой и фундаментальный способ обработки ошибок в 1С — это использование блока Попытка - Исключение - КонецПопытки. Этот механизм позволяет "перехватить" ошибку, выполнить альтернативный код (например, записать информацию о сбое) и продолжить выполнение программы, не прерывая ее аварийно.

Ключевой момент здесь — гранулярность. Не стоит оборачивать в одну большую конструкцию Попытка весь код обмена. Это плохая практика, так как при возникновении любой ошибки вы не будете знать, на каком именно объекте она произошла. Правильный подход — размещать блок Попытка-Исключение внутри цикла, который перебирает загружаемые объекты. Таким образом, ошибка в одном объекте будет обработана локально, а цикл перейдет к следующему.

Посмотрим на пример. Предположим, у нас есть массив объектов, которые нужно последовательно создать и записать в базу.


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

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

Это позволит не терять "проблемные" данные и даст возможность администратору или ответственному пользователю проанализировать причины сбоев и исправить их.

Решение 2: Обход проверок с помощью "ОбменДанными.Загрузка"

Иногда ошибки возникают не из-за нарушения целостности базы данных, а из-за срабатывания бизнес-логики, заложенной в обработчиках событий (например, ПередЗаписью). Эта логика может быть избыточной при обмене данными, так как предполагается, что данные уже прошли все проверки в системе-источнике.

Для таких случаев в платформе 1С существует специальное свойство ОбменДанными.Загрузка. Установка этого свойства в Истина для объекта перед его записью отключает вызов многих стандартных проверок и обработчиков событий.

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

Этот механизм можно эффективно комбинировать с предыдущим. Например, сначала пробовать записать объект в обычном режиме. Если возникает ошибка, залогировать ее и попробовать записать объект принудительно с флагом Загрузка = Истина.

Рассмотрим, как это может выглядеть в коде:


Попытка
    
    // Первая попытка - обычная запись со всеми проверками
    Объект.Записать();
    
Исключение
    
    // Если обычная запись не удалась, логируем ошибку
    ТекстОшибки = "Ошибка при обычной записи объекта " + Объект + ". " + ОписаниеОшибки();
    ЗаписатьВЛог(ТекстОшибки);
    
    // Вторая попытка - принудительная запись в режиме загрузки
    Попытка
        Объект.ОбменДанными.Загрузка = Истина;
        Объект.Записать();
        ЗаписатьВЛог("Объект " + Объект + " был записан принудительно в режиме загрузки.");
    Исключение
        // Если даже принудительная запись не удалась, значит, проблема серьезная
        ТекстОшибки2 = "Не удалось принудительно записать объект " + Объект + ". " + ОписаниеОшибки();
        ЗаписатьВЛог(ТекстОшибки2);
    КонецПопытки;
    
КонецПопытки;

// После записи рекомендуется вернуть флаг в исходное состояние
Если Объект.ОбменДанными.Загрузка Тогда
    Объект.ОбменДанными.Загрузка = Ложь;
КонецЕсли;

Решение 3: Предварительная проверка (валидация) данных

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

Рассмотрим несколько видов валидации.

Проверка на заполненность обязательных полей

Если вы знаете, что для корректной записи документа обязательно должны быть заполнены, например, поля "Контрагент" и "Организация", проверьте их перед вызовом метода Записать().


// ... код создания и начального заполнения объекта ...

Если НЕ ЗначениеЗаполнено(НовыйДокумент.Контрагент) Тогда
    ЗаписатьВЛог("Для объекта не заполнен Контрагент. Запись отменена.");
    Продолжить; // Переходим к следующему элементу в цикле
КонецЕсли;

Если НЕ ЗначениеЗаполнено(НовыйДокумент.Организация) Тогда
    ЗаписатьВЛог("Для объекта не заполнена Организация. Запись отменена.");
    Продолжить; // Переходим к следующему элементу в цикле
КонецЕсли;

// Если все проверки пройдены, пытаемся записать
Попытка
    НовыйДокумент.Записать();
Исключение
    // ... обработка других, непредвиденных ошибок записи ...
КонецПопытки;

Проверка структуры данных (JSON, XML)

Частая ошибка при обмене — "Поле объекта не обнаружено". Она возникает, когда в коде есть обращение к полю, которого нет в полученной структуре данных (например, из-за изменения формата на стороне источника). Таких ошибок можно избежать, проверяя наличие свойств перед обращением к ним.

Для JSON:

При работе с объектом типа Соответствие или Структура, полученным после десериализации JSON, используйте метод Свойство() для проверки.


// ДанныеJSON - это Структура или Соответствие
Если ДанныеJSON.Свойство("НомерДокумента") Тогда
    НовыйДокумент.Номер = ДанныеJSON.НомерДокумента;
Иначе
    ЗаписатьВЛог("В полученных данных отсутствует свойство 'НомерДокумента'.");
КонецЕсли;

Для XML:

При работе с XML рекомендуется использовать механизм XDTO. Он позволяет работать с данными как с типизированными объектами. У объекта XDTO также можно проверить наличие свойств через метод Свойства().


// ОбъектXDTO - результат чтения XML через ФабрикуXDTO
СвойстваОбъекта = ОбъектXDTO.Свойства();
НайденноеСвойство = СвойстваОбъекта.Найти("ДатаДокумента");

Если НайденноеСвойство <> Неопределено Тогда
    НовыйДокумент.Дата = ОбъектXDTO.ДатаДокумента;
Иначе
    ЗаписатьВЛог("В полученных XML-данных отсутствует свойство 'ДатаДокумента'.");
КонецЕсли;

Итог: Комбинированный подход

Для построения максимально надежной и отказоустойчивой системы обмена данными рекомендуется комбинировать все три описанных подхода. Идеальный алгоритм обработки одного объекта в цикле выглядит так:

  1. Валидация: Проверьте полученные данные на наличие всех обязательных полей и корректность структуры. Если данные невалидны, зафиксируйте это в логе и переходите к следующему объекту.
  2. Первая попытка записи: Оберните запись объекта в блок Попытка-Исключение. Попробуйте записать объект в штатном режиме, со всеми проверками.
  3. Обработка исключения: Если штатная запись не удалась, в блоке Исключение залогируйте подробную информацию об ошибке.
  4. Вторая попытка записи (опционально): Внутри блока Исключение можно предпринять вторую попытку записи, установив Объект.ОбменДанными.Загрузка = Истина, чтобы обойти проверки бизнес-логики. Эту попытку также следует обернуть в свой блок Попытка-Исключение.

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

← На главную