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

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

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

Выясним причину блокировки проведения

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

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

Вариант 1. Разделение логики проведения по условию количества строк

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

Посмотрим на пример реализации в процедуре ОбработкаПроведения модуля объекта:


Процедура ОбработкаПроведения(Отказ, РежимПроведения)
    
    Движения.ОстаткиНоменклатуры.Записывать = Истина;
    
    Если Товары.Количество() = 0 Тогда
        
        // Формируем движение только на основании данных шапки документа
        Движение = Движения.ОстаткиНоменклатуры.Добавить();
        Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
        Движение.Период = Дата;
        Движение.Склад = Склад;
        // Измерения, зависящие от ТЧ, остаются пустыми или заполняются значениями по умолчанию
        Движение.Номенклатура = Справочники.Номенклатура.ПустаяСсылка();
        Движение.Количество = 0;
        Движение.Сумма = СуммаДокумента;
        
    Иначе
        
        // Стандартный обход строк табличной части
        Для Каждого Стр Из Товары Цикл
            Движение = Движения.ОстаткиНоменклатуры.Добавить();
            Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
            Движение.Период = Дата;
            Движение.Склад = Склад;
            Движение.Номенклатура = Стр.Номенклатура;
            Движение.Количество = Стр.Количество;
            Движение.Сумма = Стр.Сумма;
        КонецЦикла;
        
    КонецЕсли;
    
КонецПроцедуры

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

Вариант 2. Универсальный запрос с использованием левого соединения

Рассмотрим более гибкий и архитектурно правильный способ, при котором движения всегда формируются через запрос. Чтобы обработать пустую табличную часть без ветвления кода, применим ЛЕВОЕ СОЕДИНЕНИЕ таблицы шапки документа с его табличной частью, используя функцию ЕСТЬNULL.

Разберем логику работы такого запроса:

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

Посмотрим на пример программной реализации универсального проведения:


Процедура ОбработкаПроведения(Отказ, РежимПроведения)
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Док.Ссылка КАК Ссылка,
        |   Док.Дата КАК Период,
        |   Док.Склад КАК Склад,
        |   ЕСТЬNULL(ДокТовары.Номенклатура, ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)) КАК Номенклатура,
        |   ЕСТЬNULL(ДокТовары.Количество, 0) КАК Количество,
        |   ВЫБОР
        |       КОГДА ДокТовары.НомерСтроки ЕСТЬ NULL ТОГДА Док.СуммаДокумента
        |       ИНАЧЕ ДокТовары.Сумма
        |   КОНЕЦ КАК Сумма
        |ИЗ
        |   Документ.ПоступлениеТоваров КАК Док
        |   ЛЕВОЕ СОЕДИНЕНИЕ Документ.ПоступлениеТоваров.Товары КАК ДокТовары
        |       ПО Док.Ссылка = ДокТовары.Ссылка
        |ГДЕ
        |   Док.Ссылка = &Ссылка";
        
    Запрос.УстановитьПараметр("Ссылка", Ссылка);
    РезультатЗапроса = Запрос.Выполнить();
    
    Выборка = РезультатЗапроса.Выбрать();
    
    Движения.ОстаткиНоменклатуры.Записывать = Истина;
    
    Пока Выборка.Следующий() Цикл
        Движение = Движения.ОстаткиНоменклатуры.Добавить();
        Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
        Движение.Период = Выборка.Период;
        Движение.Склад = Выборка.Склад;
        Движение.Номенклатура = Выборка.Номенклатура;
        Движение.Количество = Выборка.Количество;
        Движение.Сумма = Выборка.Сумма;
    КонецЦикла;
    
КонецПроцедуры

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

Особенности работы с итогами и производительностью

Завершая настройку проведения с пустыми значениями, обратим внимание на производительность системы:

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