При работе в крупных системах автоматизации, таких как 1С:ERP или 1С:Комплексная автоматизация, часто возникает необходимость кастомизации стандартных или создание новых печатных форм. Одной из распространенных задач является вывод специфических данных в «Акт списания материалов». Рассмотрим ситуацию, когда причина списания должна определяться динамически: если документ «Внутреннее потребление товаров» создан на основании «Регистрации несоответствий», то в качестве причины должно выводиться само несоответствие. В иных случаях должна подтягиваться стандартная причина из реквизитов документа.
В этой статье мы подробно разберем, как модифицировать программный код функции печати, изменим запрос для получения данных и внедрим алгоритм проверки типа документа. Мы пройдем по всем этапам — от анализа структуры данных до финального вывода в табличный документ.
Проанализируем текущую реализацию функции СТ_ПечатьАктСписания. В данный момент запрос собирает данные из табличной части Товары документа ВнутреннееПотреблениеТоваров, а также подтягивает цены и ответственных лиц. Причина списания сейчас берется напрямую из реквизита СТ_ПричинаСписания или СТ_ПричинаСписанияДетали основного документа.
Наша задача: изменить логику так, чтобы программа «видела» документ-основание и умела извлекать из него данные. Сложность заключается в том, что печатная форма может быть сводной, то есть объединять данные нескольких документов с разными основаниями.
Первым делом нам необходимо дополнить текст запроса в блоке выбора данных из основной таблицы документа. Нам нужно получить поле ДокументОснование (в некоторых конфигурациях это может быть Заказ или связь через ДокументыОснования). Рассмотрим, как добавить поле связи с «Регистрацией несоответствий».
Найдем в коде место, где выбираются основные реквизиты документа ВнутреннееПотреблениеТоваров, и добавим туда выборку основания. Рекомендуется использовать конструкцию ВЫРАЗИТЬ, чтобы система понимала, с каким типом данных мы работаем:
| ВнутреннееПотреблениеТоваров.Номер КАК НомерДокумента,
| ВнутреннееПотреблениеТоваров.Дата КАК ДатаДокумента,
| // Добавляем поле документа-основания
| ВнутреннееПотреблениеТоваров.ДокументОснование КАК ДокументОснование,
| // Пытаемся сразу получить Несоответствие, если основание верного типа
| ВЫРАЗИТЬ(ВнутреннееПотреблениеТоваров.ДокументОснование КАК Документ.РегистрацияНесоответствий).Несоответствие КАК ПричинаИзНесоответствия,
| ВнутреннееПотреблениеТоваров.СТ_ПричинаСписания КАК ПричинаСписания,
| ...
Использование ВЫРАЗИТЬ в запросе — это хороший тон в программировании 1С, так как это помогает оптимизировать выполнение запроса и избежать проблем с обращением через точку к полям составного типа данных.
Теперь перейдем к обработке результатов запроса. Нам нужно изменить алгоритм заполнения параметров области макета. В исходном коде заполнение происходит массово через Область.Параметры.Заполнить(ВыборкаШапка). Нам нужно внедрить проверку перед выводом области в табличный документ.
Проанализируем цикл Пока ВыборкаШапка.Следующий(). Именно здесь решается, какая информация попадет в шапку или в строки (в зависимости от настроек сводности). Рассмотрим пример реализации логики:
Пока ВыборкаШапка.Следующий() Цикл
// ... существующий код подготовки номера документа ...
Если Не Сводно Или ПервыйДокумент Тогда
// Получаем область шапки
Если Сводно Тогда
Область = Макет.ПолучитьОбласть("ШапкаСводная");
Иначе
Область = Макет.ПолучитьОбласть("Шапка");
КонецЕсли;
// Заполняем стандартные параметры
Область.Параметры.Заполнить(ВыборкаШапка);
// Внедряем нашу логику выбора причины списания
ТекПричинаСписания = "";
Если ЗначениеЗаполнено(ВыборкаШапка.ПричинаИзНесоответствия) Тогда
// Если документ создан на основании Регистрации несоответствий
ТекПричинаСписания = Строка(ВыборкаШапка.ПричинаИзНесоответствия);
ИначеЕсли ЗначениеЗаполнено(ВыборкаШапка.СТ_ПричинаСписанияДетали) Тогда
// Если есть детализированная причина
ТекПричинаСписания = ВыборкаШапка.СТ_ПричинаСписанияДетали;
Иначе
// Стандартная причина из документа
ТекПричинаСписания = Строка(ВыборкаШапка.ПричинаСписания);
КонецЕсли;
// Принудительно устанавливаем параметр в области макета
Область.Параметры.ПричинаСписания = ТекПричинаСписания;
// ... остальной код вывода области ...
КонецЕсли;
КонецЦикла;
Выясним причину, по которой данные могут отображаться некорректно в сводном режиме. Если параметр Сводно = Истина, то шапка выводится только один раз (для первого документа), а затем идут строки всех документов. Если у разных документов разные основания (один по регистрации, другой — нет), возникает вопрос: какую причину выводить в общей шапке?
Рассмотрим два варианта решения этой ситуации:
Строка).Если мы выбираем вариант с выводом в строках, код внутри цикла Пока ВыборкаСтрокиПоСсылке.Следующий() будет выглядеть следующим образом:
Пока ВыборкаСтрокиПоСсылке.Следующий() Цикл
Область = Макет.ПолучитьОбласть("Строка");
Область.Параметры.Заполнить(ВыборкаСтрокиПоСсылке);
// Переопределяем причину для каждой конкретной строки,
// основываясь на данных текущей выборки шапки
Если ТипЗнч(ВыборкаШапка.ДокументОснование) = Тип("ДокументСсылка.РегистрацияНесоответствий") Тогда
Область.Параметры.ПричинаСписания = Строка(ВыборкаШапка.ПричинаИзНесоответствия);
Иначе
Область.Параметры.ПричинаСписания = Строка(ВыборкаШапка.ПричинаСписания);
КонецЕсли;
ТабДокумент.Вывести(Область);
КонецЦикла;
Важно помнить, что в типовых конфигурациях 1С (ERP/КА) поле ДокументОснование является составным типом. Это означает, что при обращении к нему в коде 1С напрямую через ВыборкаШапка.ДокументОснование.Несоответствие, система выполнит дополнительный запрос к базе данных для каждого документа в выборке (проблема N+1). Чтобы этого избежать, мы использовали ВЫРАЗИТЬ в основном тексте запроса на Шаге 1.
Также проанализируем ситуацию, упомянутую в обсуждении: «Заказ на внутреннее потребление не всегда создан на основании регистрации несоответствия». В этом случае цепочка документов выглядит так: Регистрация несоответствий -> Заказ на внутреннее потребление -> Внутреннее потребление товаров.
Для корректной работы в такой глубокой иерархии в запросе нужно использовать левое соединение не только с основанием самого документа, но и с основанием его основания. Посмотрим, как это реализовать:
| ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЗаказНаВнутреннееПотребление КАК Заказ
| ПО ВнутреннееПотреблениеТоваров.ДокументОснование = Заказ.Ссылка
| ЛЕВОЕ СОЕДИНЕНИЕ Документ.РегистрацияНесоответствий КАК Регистрация
| ПО (ВнутреннееПотреблениеТоваров.ДокументОснование = Регистрация.Ссылка
| ИЛИ Заказ.ДокументОснование = Регистрация.Ссылка)
Такой подход позволит найти «Регистрацию несоответствий», даже если она находится на уровень выше в структуре подчиненности.
Подведем итоги. Для реализации корректного отображения причины списания мы выполнили следующие действия:
Строка() или Представление() для корректного вывода ссылочных типов в текстовое поле печатной формы.Теперь ваша печатная форма будет автоматически подстраиваться под бизнес-процесс: если списание идет по браку (через регистрацию несоответствий), ответственные лица увидят конкретный дефект, в остальных случаях — стандартную аналитику расходов. Это значительно повышает прозрачность учета и удобство работы сотрудников склада и бухгалтерии.