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

Программист 1С v8.3 (Обычные формы) Бухгалтерский учет IT и автоматизация бизнеса
← На главную

При загрузке или пакетной обработке данных из внешних источников (например, таблиц Excel) часто возникает типовая задача: проанализировать входящую строку, найти соответствующий элемент в информационной базе и создать документ только в том случае, если объект найден и прошел все проверки. Начинающие разработчики нередко сталкиваются с путаницей в логике: создав объект в памяти заранее, они пытаются найти способ «отменить» или «отсеять» документ при невыполнении условий.

Разберем детально, как устроен жизненный цикл объектов в платформе 1С:Предприятие, почему для отмены записи не требуются специальные директивы и как правильно структурировать алгоритм обработки.

Жизненный цикл документа в оперативной памяти

Вызов метода СоздатьДокумент() менеджера документов создает экземпляр объекта исключительно в оперативной памяти приложения. На этом этапе никаких изменений в базе данных СУБД не происходит. Физическая вставка строк в таблицы базы данных выполняется строго в момент вызова метода Записать().

Рассмотрим важные следствия этого механизма:

  1. Если метод Записать() не вызывается, документ никогда не попадет в базу данных. «Удалять» или специально «отменять» его не нужно — платформа автоматически очистит память через сборщик мусора при выходе из процедуры или на следующей итерации цикла.
  2. Параметр Отказ, с помощью которого отменяется запись, существует только внутри предопределенных обработчиков событий (например, ПередЗаписью(Отказ, РежимЗаписи)). В произвольном коде обработок или модулей переменной Отказ нет, а логика ветвления управляется стандартными операторами Если ... Тогда, Продолжить или Возврат.
  3. Создание документа инициирует внутренние обработчики платформы (включая ОбработкаЗаполнения) и выделяет системные ресурсы. Вызывать СоздатьДокумент() до того, как проверены базовые условия (например, наличие элемента справочника), является избыточным действием.

Вариант 1. Использование оператора Продолжить в цикле

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


Для Каждого СтрокаДанных Из ТаблицаЗагрузки Цикл
    
    // 1. Ищем элемент справочника
    ОсновноеСредство = Справочники.ОсновныеСредства.НайтиПоРеквизиту("ИнвентарныйНомер", СтрокаДанных.ИнвентарныйНомер);
    
    // 2. Проверяем, найден ли элемент
    Если Не ЗначениеЗаполнено(ОсновноеСредство) Тогда
        Сообщить("Основное средство с инвентарным номером " + СтрокаДанных.ИнвентарныйНомер + " не найдено. Пропуск строки.");
        Продолжить;
    КонецЕсли;
    
    // 3. Дополнительная валидация данных
    Если ОсновноеСредство.Наименование <> Лев(СтрокаДанных.Наименование, 80) Тогда
        Сообщить("Расхождение в наименовании для инвентарного номера " + СтрокаДанных.ИнвентарныйНомер);
        Продолжить;
    КонецЕсли;
    
    // 4. Создаем и записываем документ только при успешном прохождении проверок
    ДокОС = Документы.ОС_ВводИсторииПереоценки.СоздатьДокумент();
    ДокОС.Дата = ТекущаяДата();
    ДокОС.Учреждение = СсылкаНаУчреждение;
    ДокОС.ОС = ОсновноеСредство;
    
    ДокОС.Записать(РежимЗаписиДокумента.Запись);
    
КонецЦикла;

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

Вариант 2. Ветвление логики через условие Если ... Иначе

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


ОсновноеСредство = Справочники.ОсновныеСредства.НайтиПоРеквизиту("ИнвентарныйНомер", тИнвентарныйНомер);

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

Рекомендации по повышению надежности и производительности

Разберем технические нюансы, которые необходимо учитывать при реализации подобных загрузок:

  1. Корректная проверка пустых ссылок: Сравнение основн = спрОС.ПустаяСсылка() требует наличия инициализированного менеджера справочника. Надежнее использовать метод самой ссылки ОсновноеСредство.Пустая() либо системную функцию Не ЗначениеЗаполнено(ОсновноеСредство), которая корректно обрабатывает пустые ссылки, Неопределено и Null.
  2. Оптимизация поиска элементов: Метод НайтиПоРеквизиту() внутри цикла обращается к базе данных отдельным запросом на каждом шаге. Если строк много, это приведет к просадке производительности. Кроме того, поиск работает быстро только при включенном свойстве реквизита «Индексировать». Для обработки больших массивов данных эффективнее предварительно загрузить все номера в массив и выбрать существующие элементы одним запросом с помощью конструкции В (&МассивНомеров).
  3. Работа с внешними приложениями: Вызовы методов COM-объектов (например, Excel.SaveAs()) работают крайне медленно из-за межпроцессного взаимодействия и дисковых операций ввода-вывода. Сохранение файла Excel следует выполнять один раз — после полного завершения цикла обработки строк, а не на каждой итерации при возникновении ошибки.
← На главную