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