При разработке печатных форм в 1С часто возникает задача выводить не все данные, а только те, которые соответствуют определенным условиям. Например, печатать строки из таблицы или из реквизитов документа только в том случае, если количество в них не равно нулю. Рассмотрим подробнее, как правильно реализовать такой условный вывод и какие распространённые ошибки могут возникнуть на этом пути.
Наш пользователь столкнулся с проблемой, когда попытка скрыть строки с нулевым количеством с помощью свойства Видимость = ложь приводила к непредсказуемым результатам, особенно если макет печатной формы содержал дополнительные области сверху (заголовки, шапки). Разберем ситуацию и предложим эффективные решения.
Наш пользователь изначально пытался использовать следующий код:
если Строка(Шапка.Параметры.Количество)="0" тогда
ОбластьСтрока=ТабДок.Область("R4");
ОбластьСтрока.Видимость=ложь;
конецесли;
Используя ОбластьСтрока.Видимость=ложь, мы пытаемся управлять видимостью *области макета*, а не уже *выведенной области* в табличном документе. Когда мы вызываем ТабДок.Вывести(Область), мы добавляем копию этой области макета в формируемый табличный документ. После вывода, управление видимостью исходной области макета уже не влияет на то, что уже попало в табличный документ. Если же такое решение "работало" на пустом макете, это скорее совпадение или некая особенность его структуры, которая маскировала проблему.
Главный принцип формирования печатных форм в 1С: мы строим табличный документ поэлементно. Если какая-то часть документа не должна быть показана, мы ее просто не выводим.
Также обратим внимание на условие Строка(Шапка.Параметры.Количество)="0". Сравнение чисел как строк может привести к ошибкам. Например, если количество будет "0.00" или будет иметь другой строковый формат, это условие не сработает. Всегда сравнивайте числа с числами: Шапка.Параметры.Количество = 0.
Наиболее правильный и эффективный подход заключается в том, чтобы выводить область в табличный документ только тогда, когда выполняется нужное условие. Это гарантирует, что ненужные строки никогда не попадут в итоговую печатную форму.
Рассмотрим по шагам, как адаптировать этот подход к ситуации, когда данные представлены в виде отдельных реквизитов документа (например, Количество1, Количество2, ..., Количество20), а не в виде табличной части.
Подготовка данных и областей макета:
Начнем с получения данных. В нашем случае, пользователь получает их запросом:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Документ1.Количество1,
| Документ1.Количество2,
| Документ1.Количество3 // ... и т.д. до Количество20
| ИЗ
| Документ.Документ1 как Документ1
|ГДЕ
|Документ1.Ссылка В (&Ссылка)";
Запрос.Параметры.Вставить("Ссылка", Ссылка);
Выборка = Запрос.Выполнить().Выбрать();
// Переходим к первой записи выборки, чтобы заполнить параметры
Если Выборка.Следующий() Тогда
// Теперь Шапка.Параметры можно заполнить
КонецЕсли;
Предположим, что в макете у нас есть отдельные области для каждой детали, например, ОбластьДеталь1, ОбластьДеталь2 и так далее, каждая со своими параметрами (НазваниеДетали, КоличествоДетали).
Условный вывод для каждого реквизита:
Вместо того чтобы сначала выводить всю шапку, а затем пытаться скрывать строки, мы будем проверять условие для каждого реквизита и только после этого выводить соответствующую область. Если у нас есть параметры в области, их нужно заполнять перед каждым выводом. Поскольку у пользователя используется Шапка.Параметры.Заполнить(Выборка), это означает, что все параметры (включая Количество1, Количество2) уже доступны через объект Шапка.Параметры. Но так как каждая деталь - это отдельная строка, для каждой детали потребуется своя область.
Давайте адаптируем подход. Если все детали находятся в одной области Шапка, и каждый реквизит КоличествоX соответствует параметру КоличествоX в этой области, то такой подход становится сложнее. Проще, если каждая деталь имеет свою *отдельную область макета*. Предположим, что у нас есть области: ОбластьСтрокаДетали1, ОбластьСтрокаДетали2 и т.д.
// ... Получаем Выборку, переходим к первой записи Выборка.Следующий() ...
// Получаем общую шапку документа, если она есть и всегда выводится
ОбластьЗаголовок = Макет.ПолучитьОбласть("Заголовок");
ТабДок.Вывести(ОбластьЗаголовок); // Выводим всегда
// Если есть общая Шапка с датой/номером, которая всегда выводится
ОбластьОбщаяШапка = Макет.ПолучитьОбласть("ОбщаяШапка");
ОбластьОбщаяШапка.Параметры.Заполнить(Выборка); // Заполняем общие параметры
ТабДок.Вывести(ОбластьОбщаяШапка); // Выводим всегда
// Теперь обрабатываем детали
// Для каждой детали создаем отдельную область в макете
// и заполняем ее параметры перед выводом.
// Деталь 1
Если Выборка.Количество1 <> 0 Тогда
ОбластьДеталь1 = Макет.ПолучитьОбласть("ОбластьДеталь1");
ОбластьДеталь1.Параметры.НазваниеДетали = Выборка.НазваниеДетали1; // Предполагается, что есть такой реквизит
ОбластьДеталь1.Параметры.Количество = Выборка.Количество1;
ТабДок.Вывести(ОбластьДеталь1);
КонецЕсли;
// Деталь 2
Если Выборка.Количество2 <> 0 Тогда
ОбластьДеталь2 = Макет.ПолучитьОбласть("ОбластьДеталь2");
ОбластьДеталь2.Параметры.НазваниеДетали = Выборка.НазваниеДетали2;
ОбластьДеталь2.Параметры.Количество = Выборка.Количество2;
ТабДок.Вывести(ОбластьДеталь2);
КонецЕсли;
// ... и так далее для всех 20 деталей ...
// Деталь 20
Если Выборка.Количество20 <> 0 Тогда
ОбластьДеталь20 = Макет.ПолучитьОбласть("ОбластьДеталь20");
ОбластьДеталь20.Параметры.НазваниеДетали = Выборка.НазваниеДетали20;
ОбластьДеталь20.Параметры.Количество = Выборка.Количество20;
ТабДок.Вывести(ОбластьДеталь20);
КонецЕсли;
Этот подход гарантирует, что в табличный документ будут добавлены только те строки, которые соответствуют условию. Это гораздо более предсказуемый и правильный способ формирования печатных форм.
Пример из форума, адаптированный к вашему случаю:
Пользователь (9) предложил общую структуру:
Пока Выборка.Следующий() Цикл
Если Выборка.Количество <> 0 Тогда
ТабДок.Вывести(Область);
КонецЕсли;
КонецЦикла;
Поскольку у нас не табличная часть, а отдельные реквизиты, мы не можем использовать цикл Пока Выборка.Следующий() для каждой детали. Вместо этого, мы делаем последовательные проверки, как показано выше. Однако, если бы у вас была табличная часть, этот код был бы идеален для итерации по ее строкам.
На форуме справедливо заметили, что хранение однотипных данных (20 деталей с количествами) в виде отдельных реквизитов Количество1, Количество2 и т.д. является антипаттерном. Это значительно усложняет разработку, поддержку и формирование отчетов. Наиболее оптимальным и гибким решением является перевод этих данных в табличную часть документа.
Наш пользователь выразил опасения по поводу использования табличной части, ссылаясь на специфические требования:
Не заставлять оператора выбирать детали из справочника, а выдавать готовый список под выбранную модель.
Это требование легко реализуется и с табличной частью. При выборе модели на форме документа, мы можем программно заполнять табличную часть нужными деталями. Например, в обработчике события поля "Модель":
&НаСервере
Процедура МодельПриИзмененииНаСервере(Источник)
// Очищаем существующие строки, если модель меняется
Объект.ТабличнаяЧастьДетали.Очистить();
// Получаем список деталей для выбранной модели из регистра сведений или другого источника
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СоставМоделей.Деталь,
| СоставМоделей.КоличествоПоУмолчанию,
| СоставМоделей.МаксимальноеКоличество
|ИЗ
| РегистрСведений.СоставМоделейКакДетали КАК СоставМоделей
|ГДЕ
| СоставМоделей.Модель = &Модель";
Запрос.УстановитьПараметр("Модель", Объект.Модель);
ВыборкаДеталей = Запрос.Выполнить().Выбрать();
Пока ВыборкаДеталей.Следующий() Цикл
НоваяСтрока = Объект.ТабличнаяЧастьДетали.Добавить();
НоваяСтрока.Деталь = ВыборкаДеталей.Деталь;
НоваяСтрока.Количество = ВыборкаДеталей.КоличествоПоУмолчанию; // Установим 0 или другое значение
// МаксимальноеКоличество можно сохранить в ТЧ или получать динамически
КонецЦикла;
КонецПроцедуры
Таким образом, оператор увидит уже заполненную таблицу, а не пустую.
Не давать оператору писать что угодно в количество, а ограничить выбор, но у разных деталей разное максимальное количество (от 2 до 4).
Это также реализуемо. Для колонки "Количество" в табличной части можно использовать обработчики событий или динамические свойства:
Обработчик ПриИзменении:
Вы можете добавить обработчик ПриИзменении для поля "Количество" в табличной части формы. В этом обработчике вы можете получить текущую деталь в строке и проверить введенное количество на соответствие максимальному значению для этой детали:
&НаКлиенте
Процедура ТабличнаяЧастьДеталиКоличествоПриИзменении(Элемент)
ТекущиеДанные = Элементы.ТабличнаяЧастьДетали.ТекущиеДанные;
Если ТекущиеДанные = Неопределено Тогда
Возврат;
КонецЕсли;
// Получаем максимальное количество для текущей детали (можно хранить в ТЧ
// или получать из справочника/регистра)
МаксимальноеКоличество = ПолучитьМаксимальноеКоличествоДляДетали(ТекущиеДанные.Деталь);
Если ТекущиеДанные.Количество > МаксимальноеКоличество Тогда
Сообщение = Новый СообщениеПользователю();
Сообщение.Текст = "Количество не может превышать " + МаксимальноеКоличество + " для детали " + ТекущиеДанные.Деталь;
Сообщение.Поле = "Количество";
Сообщение.УстановитьОбъект(Элемент);
Сообщение.Вывести();
ТекущиеДанные.Количество = МаксимальноеКоличество; // Можно сбросить до максимума
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПолучитьМаксимальноеКоличествоДляДетали(Деталь)
// Пример: получаем из регистра сведений
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| МаксимальноеКоличество
|ИЗ
| РегистрСведений.СоставМоделейКакДетали
|ГДЕ
| Деталь = &Деталь";
Запрос.УстановитьПараметр("Деталь", Деталь);
Результат = Запрос.Выполнить().Выбрать();
Если Результат.Следующий() Тогда
Возврат Результат.МаксимальноеКоличество;
Иначе
Возврат 999; // Значение по умолчанию или ошибка
КонецЕсли;
КонецФункции;
Динамические свойства элемента формы:
Можно использовать свойство ОграничениеЗначения для элемента формы, привязанного к колонке табличной части. Это свойство может быть установлено динамически для каждой строки таблицы. Для этого можно использовать обработчик ПриПолученииДанных элемента формы "Таблица" или установить его в ПриСозданииНаСервере для каждого элемента коллекции элементов формы, представляющих строки табличной части.
Более простой способ — использовать поле ввода с типом "Число" и свойством "МинимальноеЗначение" и "МаксимальноеЗначение". Вы можете хранить максимальное количество как дополнительный реквизит табличной части (который не будет выводиться на печать), и при изменении строки или детали обновлять свойства поля "Количество".
Таким образом, переход на табличную часть не только упростит формирование печатных форм, но и позволит более гибко управлять бизнес-логикой на форме.
Если мы переходим на табличную часть, формирование печатной формы становится значительно проще и чище:
Получаем область шапки и выводим ее:
ОбластьШапка = Макет.ПолучитьОбласть("Шапка");
ОбластьШапка.Параметры.Заполнить(ОбъектДокумента); // Заполняем параметры из реквизитов документа
ТабДок.Вывести(ОбластьШапка);
Получаем область строки табличной части:
ОбластьСтрокаТЧ = Макет.ПолучитьОбласть("СтрокаТабличнойЧасти");
Перебираем строки табличной части документа, применяя условие:
Для Каждого СтрокаТЧ Из ОбъектДокумента.ТабличнаяЧастьДетали Цикл
Если СтрокаТЧ.Количество <> 0 Тогда // Проверяем условие
ОбластьСтрокаТЧ.Параметры.Заполнить(СтрокаТЧ); // Заполняем параметры из текущей строки ТЧ
ТабДок.Вывести(ОбластьСтрокаТЧ); // Выводим строку, если условие выполнено
КонецЕсли;
КонецЦикла;
Этот код является наглядным примером из сообщения (9) и идеально подходит для работы с табличными частями. Он элегантен, легко читаем и масштабируем.
Мы выяснили, что основная проблема нашего пользователя заключалась в неправильном применении свойства Видимость для управления элементами печатной формы. Вместо того чтобы скрывать уже выведенные области, необходимо заранее принимать решение о их выводе.
Ключевые моменты для успешного условного вывода:
Выводите только то, что нужно: Используйте условные операторы Если ... Тогда перед вызовом ТабДок.Вывести(). Если условие не выполняется, метод Вывести() просто не вызывается, и область не попадает в табличный документ.
Правильное сравнение типов: Всегда сравнивайте числовые значения с числовыми (например, Количество = 0), а не строковые представления чисел. Это предотвращает ошибки, связанные с форматированием.
Структурируйте данные: Для однотипных повторяющихся данных (как детали с количествами) всегда предпочтительнее использовать табличные части документа. Это значительно упрощает как логику работы с данными на форме, так и формирование печатных форм и отчетов. Требования по предзаполнению и динамическим ограничениям для полей легко реализуются для табличных частей через обработчики событий формы.
Именование областей: В макете давайте осмысленные и уникальные имена областям, особенно если у вас много однотипных строк, которые выводятся по условию. Это поможет избежать путаницы и ошибок.
Применяя эти подходы, мы сможем создавать гибкие и корректно работающие печатные формы, которые будут выводить информацию именно так, как нам необходимо, без "фокусов" и неожиданного поведения.