Как заполнить реквизит табличной части при нажатии кнопки печать

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

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

Анализ задачи и выбор места для доработки

Прежде всего, проанализируем ситуацию. У нас есть бизнес-процесс (или документ), в котором имеется табличная часть Журнал. В этой таблице есть реквизит ДатаПередачи. Печатная форма создана с помощью стандартного конструктора печати. Наша цель — внедрить код, который будет изменять данные объекта перед тем, как пользователь увидит сформированный табличный документ.

Существует два основных пути реализации: изменение данных непосредственно в форме (на клиенте) или работа с объектом на сервере в модуле менеджера. Рассмотрим по шагам наиболее надежные методы.

Способ 1. Реализация логики в модуле команды печати

Когда вы используете конструктор печати, создается Команда. Код команды выполняется на клиенте, а затем вызывает серверную процедуру для формирования макета. Посмотрим на пример кода, который позволяет обойти строки табличной части и заполнить дату.

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


&НаКлиенте
Процедура ОбработкаКоманды(ПараметрКоманды, ПараметрыВыполненияКоманды)
    
    // ПараметрКоманды в данном случае — это ссылка на наш объект (документ или бизнес-процесс)
    // Перед печатью нам нужно выполнить действия на сервере по заполнению данных
    ЗаполнитьДатуПередачиНаСервере(ПараметрКоманды);
    
    // Стандартный блок вызова печати, созданный конструктором
    ТабДок = Новый ТабличныйДокумент;
    Печать(ТабДок, ПараметрКоманды);
    
    ТабДок.ОтображатьСетку = Ложь;
    ТабДок.Показать();
    
    // Важно: оповещаем систему, что данные объекта изменились, 
    // чтобы открытые формы обновили свое содержимое
    ОповеститьОбИзменении(ПараметрКоманды);
    
КонецПроцедуры

&НаСервере
Процедура ЗаполнитьДатуПередачиНаСервере(СсылкаНаОбъект)
    
    // Получаем объект для редактирования
    ОбъектМанипуляции = СсылкаНаОбъект.ПолучитьОбъект();
    
    Для Каждого ТекСтрока Из ОбъектМанипуляции.Журнал Цикл
        // Проверяем, нужно ли перезаписывать дату, если она уже заполнена
        Если Не ЗначениеЗаполнено(ТекСтрока.ДатаПередачи) Тогда
            ТекСтрока.ДатаПередачи = ТекущаяДата();
        КонецЕсли;
    КонецЦикла;
    
    // Если были изменения, записываем объект в базу данных
    Если ОбъектМанипуляции.Модифицированность() Тогда
        ОбъектМанипуляции.Записать();
    КонецЕсли;
    
КонецПроцедуры

В этом примере мы используем метод ПолучитьОбъект(), так как работа со ссылкой не позволяет изменять данные. Метод ЗначениеЗаполнено() помогает нам избежать случайной перезаписи уже существующих дат, если печатная форма формируется повторно.

Способ 2. Модификация в модуле менеджера

Иногда логичнее встроить заполнение данных непосредственно в процедуру Печать, которая находится в модуле менеджера. Это гарантирует, что при любом способе вызова печати (из формы или из списка) данные будут актуализированы.

Выясним причину, почему это удобно: модуль менеджера уже получает ссылку на объект. Мы можем дописать логику в самом начале процедуры. Рассмотрим фрагмент кода в модуле менеджера:


Процедура Печать(ТабДок, Ссылка) Экспорт
    
    // 1. Обновляем данные в базе перед формированием запроса для печати
    Объект = Ссылка.ПолучитьОбъект();
    Изменено = Ложь;
    
    Для Каждого СтрокаЖурнала Из Объект.Журнал Цикл
        Если СтрокаЖурнала.ДатаПередачи = '00010101' Тогда // Альтернативная проверка на пустую дату
            СтрокаЖурнала.ДатаПередачи = ТекущаяДатаСеанса();
            Изменено = Истина;
        КонецЕсли;
    КонецЦикла;
    
    Если Изменено Тогда
        Объект.Записать();
    КонецЕсли;
    
    // 2. Далее идет стандартный код формирования печатной формы
    Макет = ПолучитьМакет("Печать");
    Запрос = Новый Запрос;
    // ... текст запроса ...
    // Запрос выберет уже обновленные данные из базы данных
КонецПроцедуры

Обратите внимание на использование ТекущаяДатаСеанса(). В клиент-серверном варианте работы это более корректный метод, чем просто ТекущаяДата(), так как он учитывает часовой пояс пользователя.

Важные нюансы и риски

При реализации автоматического заполнения реквизитов при печати необходимо учитывать несколько критических моментов:

  1. Права доступа: Пользователь, нажимающий кнопку "Печать", должен иметь права на редактирование данного документа. Если у пользователя права только на просмотр, метод Записать() вызовет ошибку прав доступа.
  2. Блокировки данных: Если в момент нажатия кнопки "Печать" этот же документ редактируется другим пользователем, попытка записи объекта приведет к конфликту блокировок.
  3. Обновление экранной формы: Если пользователь открыл форму документа, нажал "Печать" и данные в базе изменились, в самой открытой форме он увидит старые значения, пока не переоткроет её или не нажмет "Обновить". Чтобы этого избежать, используйте метод ОповеститьОбИзменении() или в самой форме вызывайте ЭтаФорма.Прочитать() после печати.
  4. Транзакционность: Запись объекта внутри процедуры печати — это дополнительная транзакция. Если ваша печатная форма формируется очень долго, это может замедлить работу системы.

Работа с активной строкой

Проанализируем ситуацию, когда дату нужно проставить не во всей табличной части, а только в той строке, которую выбрал пользователь. В модуле формы мы можем получить текущие данные таблицы через элемент управления Элементы.Журнал.ТекущиеДанные.

Рассмотрим, как передать эти данные в команду:


&НаКлиенте
Процедура КомандаПечатьСтроки(Команда)
    
    ТекущаяСтрока = Элементы.Журнал.ТекущиеДанные;
    
    Если ТекущаяСтрока = Неопределено Тогда
        Предупреждение("Выберите строку в списке!");
        Возврат;
    КонецЕсли;
    
    // Передаем идентификатор строки на сервер для точечного изменения
    ЗаполнитьДатуДляОднойСтрокиНаСервере(Объект.Ссылка, ТекущаяСтрока.ПолучитьИдентификатор());
    
КонецПроцедуры

На сервере мы найдем строку по идентификатору в объекте и обновим только её. Это более "щадящий" метод изменения данных, если табличная часть содержит сотни строк.

Итоги

Мы разобрали, как программно "достучаться" до реквизитов табличной части при выполнении печати. Главный секрет успеха заключается в правильном переходе от Ссылки к Объекту, выполнении цикла Для Каждого... Из... Цикл и обязательном вызове метода Записать(). Не забывайте про проверку ЗначениеЗаполнено(), чтобы не искажать историю данных при повторном открытии макета.

← На главную