Как доработать печатную форму счета-фактуры в 1С:ERP и вывести дополнительное поле?

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

При работе с современными конфигурациями, такими как 1С:ERP, Комплексная автоматизация или Управление торговлей 11, разработчики часто сталкиваются с трудностями при поиске механизмов печати регламентированных форм. Задача кажется простой: вывести дополнительное поле (например, из договора контрагента) в печатную форму "Счет-фактура выданный". Однако, открыв модуль документа, мы часто не находим там ожидаемого кода формирования макета. Разберем подробно, как устроена эта подсистема и как правильно реализовать доработку, не нарушая обновляемость конфигурации.

Почему мы не находим макет в документе?

Первое, с чем мы сталкиваемся — это отсутствие макета в самом документе СчетФактураВыданныйАванс или СчетФактураВыданный. Это связано с архитектурным решением 1С для унификации печатных форм. Поскольку форма счета-фактуры (постановления №1137, №534 и др.) едина для всех видов операций (реализация, аванс, корректировка), она вынесена в общие механизмы.

Давайте определим, где искать исходные объекты:

  1. Макет: Он находится в ветке Общие макеты (CommonTemplates). Искать следует по названиям, начинающимся на ПФ_MXL_СчетФактура.... Обычно актуальный макет содержит в имени номер постановления или год (например, ПФ_MXL_СчетФактура1137_2017).
  2. Код формирования: Основная логика расположена не в модуле менеджера документа, а в обработке ПечатьОбщихФорм или в общих модулях, связанных с учетом НДС (например, УчетНДСВызовСервера, УчетНДСФормированиеПечатныхФорм).

Модуль менеджера конкретного документа (например, СчетФактураВыданныйАванс) обычно содержит лишь "точку входа" — процедуру, которая подготавливает данные и передает управление в общий механизм печати.

Выбор стратегии доработки: ВПФ или Расширение?

Рассмотрим два основных пути решения задачи, которые обсуждались разработчиками, и выберем оптимальный.

Вариант 1: Внешняя печатная форма (ВПФ)

Традиционный подход, при котором мы копируем весь типовой код и макет во внешнюю обработку.
Минусы: Код формирования счета-фактуры в ERP чрезвычайно сложен. Он содержит огромные запросы, временные таблицы и логику, разбросанную по нескольким общим модулям. При каждом обновлении законодательства (новая строка в СФ, счет-фактура в редакции постановления 26, прослеживаемость, ГТД) типовой код меняется. Если мы используем ВПФ, наша форма мгновенно устаревает, и мы вынуждены заново копировать и адаптировать код. Это трудоемко и рискованно.

Вариант 2: Расширение конфигурации

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

Реализация через Расширение: Пошаговое руководство

Мы будем использовать метод "пост-обработки" табличного документа. Это самый безопасный способ: мы даем типовому механизму сформировать стандартную печатную форму, а затем программно находим нужное место и вписываем туда наше значение. Это гарантирует, что при обновлении релизов 1С (если не изменилась структура самого макета визуально) наш код продолжит работать.

Шаг 1. Подготовка расширения

Убедимся, что наше расширение активно и в нем отключен "Безопасный режим" (если мы планируем использовать серверные вызовы, которые могут требовать привилегий, хотя для печати это не всегда критично). Реквизит договора, значение которого мы хотим вывести, уже должен быть в расширении.

Шаг 2. Перехват формирования печатной формы

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

Однако, для точечного изменения удобнее использовать аннотацию &После для процедуры формирования конкретной печатной формы. Если мы говорим о механизме БСП, то часто перехватывают процедуру в модуле менеджера документа, например Печать(), но там формируется коллекция. Более глубокий уровень — перехват процедур заполнения.

Рассмотрим универсальный вариант: перехват в Общем модуле, отвечающем за формирование СФ, или использование события ОбработкаПечати в модуле менеджера, если мы хотим модифицировать результат.

Но самый надежный способ для вставки "сверху" — это найти процедуру, которая строит табличный документ. Например, в УчетНДСФормированиеПечатныхФорм. Но проще всего "поймать" готовый табличный документ на выходе из процедуры печати в модуле менеджера объекта (если она экспортная) или внедриться в процесс заполнения.

Давайте используем подход изменения уже сформированного документа через расширение модуля менеджера документа СчетФактураВыданныйАванс. Найдем там процедуру Печать.


&После("Печать")
Процедура Расш_Печать(МассивОбъектов, ПараметрыПечати, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода)
    
    // Перебираем коллекцию, чтобы найти нужную нам форму Счета-фактуры
    Для Каждого СтрокаКоллекции Из КоллекцияПечатныхФорм Цикл
        
        // Проверяем имя макета (обычно это "СчетФактура")
        Если СтрокаКоллекции.ИмяВРЕГ = ВРег("СчетФактура") ИЛИ СтрокаКоллекции.ИмяВРЕГ = "СЧЕТФАКТУРА1137" Тогда
            
            // Получаем сформированный табличный документ
            ТабДок = СтрокаКоллекции.ТабличныйДокумент;
            
            // Вызываем нашу процедуру доработки
            ДополнитьПечатнуюФормуСчетФактура(ТабДок, МассивОбъектов);
            
        КонецЕсли;
        
    КонецЦикла;
    
КонецПроцедуры

Шаг 3. Логика добавления поля (ДополнитьПечатнуюФормуСчетФактура)

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

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


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

КонецПроцедуры

Альтернативный метод: Использование процедур заполнения

В сообщениях обсуждения (особенно сообщение 14) упоминался более "тонкий" метод. В некоторых конфигурациях (зависит от версии БСП и ERP) в модулях менеджеров есть процедуры вроде ЗаполнитьРеквизитыПодвалаСчетФактура.

Если такие процедуры доступны и экспортны, их можно перехватить через &После. В параметрах этих процедур обычно передается структура данных, которая затем выводится в макет.

Пример логики:

  1. Перехватываем процедуру заполнения.
  2. В переданную структуру параметров добавляем свой ключ и значение.
  3. Но! Чтобы это значение вывелось на печать, оно должно присутствовать в Макете.

Тут возникает проблема: типовой макет не содержит параметра для нашего поля. Значит, нам придется:

Итоги и рекомендации

Подведем итог. Чтобы вывести поле из договора (который доработан в расширении) в печатную форму счета-фактуры на аванс:

  1. Не делайте ВПФ копированием кода. Это приведет к ошибкам учета НДС при обновлении конфигурации.
  2. Используйте расширение. В модуле менеджера документа (или общем модуле печати) перехватите окончание формирования печати (&После).
  3. Получите данные отдельным запросом. Не пытайтесь вклиниться в гигантские типовые запросы формирования печатных форм. Сделайте легкий запрос к вашему расширению по Ссылке документа.
  4. Модифицируйте готовый ТабличныйДокумент. Используйте методы НайтиТекст или обращение по адресам ячеек, чтобы вставить ваше значение в нужное место формы. Это сохранит легитимность формы при обновлении законодательства, так как "скелет" формы останется типовым.
← На главную