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