Разработка внешних печатных форм (ВПФ) — одна из наиболее частых задач, с которой сталкиваются как начинающие программисты, так и бухгалтеры, решившие освоить азы конфигурирования в среде «1С:Предприятие 8». На первый взгляд задача кажется простой: скопировать макет, написать пару строк кода для заполнения параметров и вывести результат на экран. Однако при работе с типовыми конфигурациями (например, «1С:Бухгалтерия предприятия 3.0») разработчики часто сталкиваются с неочевидным поведением системы.
В этой статье мы подробно разберем две типичные проблемы, возникающие при создании внешней печатной формы для документа «Оказание услуг»:
Получатель или Контрагент напрямую через ссылку на документ.Давайте вместе разберемся в причинах этих ошибок и найдем изящные способы их решения.
В платформе «1С:Предприятие» номера документов хранятся в полнотекстовом формате, чтобы обеспечить уникальность нумерации в рамках всей базы данных и различных организаций. Полный номер документа может выглядеть как 00БП-000001 или ОФ00-000025. Здесь присутствуют:
БП);ОФ);Если мы пишем код напрямую, обращаясь к реквизиту номера:
ОбластьШапка.Параметры.НомерДокумента = СсылкаНаОбъект.Номер;
Система послушно выведет весь этот технический мусор на печать. Клиентам и бухгалтерам это категорически не нравится — им нужен красивый, «чистый» номер (например, просто «1» или «25»).
Для приведения номера к человекочитаемому виду в современных конфигурациях, использующих Библиотеку стандартных подсистем (БСП), разработан специальный общий модуль. Нам не нужно самостоятельно писать сложные алгоритмы по обрезке строк с помощью функций Сред() или Лев(). Достаточно использовать готовую функцию общего модуля.
Рассмотрим, как правильно преобразовать номер для вывода в печатную форму:
// Очищаем номер от префиксов и лидирующих нулей
ОчищенныйНомер = ПрефиксацияОбъектовКлиентСервер.НомерНаПечать(СсылкаНаОбъект.Номер, Истина, Истина);
ОбластьШапка.Параметры.НомерДокумента = ОчищенныйНомер;
Проанализируем параметры функции НомерНаПечать:
СсылкаНаОбъект.Номер).Истина) — указывает системе на необходимость удаления префикса организации.Истина) — указывает на необходимость удаления префикса информационной базы.Применение этого метода гарантирует, что на печать уйдет только чистый порядковый номер.
Перейдем ко второй, более серьезной ошибке. Когда разработчик пытается получить контрагента кодом:
ОбластьШапка.Параметры.ПредставлениеПолучателя = СсылкаНаОбъект.Получатель;
1С аварийно завершает работу с ошибкой: «Поле объекта не обнаружено (Получатель)». Почему так происходит?
Всё дело в специфике самого документа «Оказание услуг». В отличие от стандартного документа «Реализация товаров и услуг», который оформляется на одного конкретного покупателя, документ «Оказание услуг» предназначен для группового ввода операций. Он используется, например, когда коммунальное предприятие или интернет-провайдер в конце месяца выставляет одинаковые услуги (акт и счет) сразу сотням своих абонентов.
Из-за такой архитектуры в шапке документа физически отсутствуют реквизиты Контрагент, Получатель, Договор или Сумма. Все эти сведения находятся внутри табличной части документа, которая называется Контрагенты. При этом колонка, хранящая ссылку на клиента, называется именно Контрагент.
Попытка обратиться к получателю напрямую через СсылкаНаОбъект — это грубейшая логическая ошибка, так как система просто не знает, какого именно контрагента из табличной части вы хотите напечатать в данный момент.
Чтобы наша внешняя печатная форма работала корректно, мы должны построить алгоритм так, чтобы программа обходила всю табличную часть Контрагенты нашего документа, получала данные по каждой строке и формировала отдельный лист акта (или счета) для каждого клиента.
Посмотрим на пример реализации такого обхода:
Для Каждого СтрокаТаблицы Из СсылкаНаОбъект.Contragenty Цикл // Обращаемся к табличной части "Контрагенты"
// Получаем ссылку на текущего контрагента из строки
ТекущийКонтрагент = СтрокаТаблицы.Контрагент;
// Дальнейший код обработки данных по конкретному контрагенту...
КонецЦикла;
Теперь разберем, как получить полные сведения о контрагенте (его ИНН, КПП, адрес, банковские реквизиты) для вывода красивого представления в печатную форму. Для этого воспользуемся встроенными механизмами конфигурации «1С:Бухгалтерия предприятия».
Ниже приведем готовый к использованию, структурированный фрагмент кода для модуля вашей внешней печатной формы. Мы объединили решение обеих проблем в один рабочий алгоритм.
Функция Печать(МассивОбъектов, КоллекцияПечатныхФорм) Экспорт
// Задаем параметры макета
ИмяМакета = "ПФ_MXL_АктОказанияУслуг";
ТабличныйДокумент = Новый ТабличныйДокумент;
ТабличныйДокумент.ИмяПараметровПечати = "ПАРАМЕТРЫ_ПЕЧАТИ_ОказаниеУслуг";
// Получаем макет обработки (он должен быть добавлен в дерево макетов вашей ВПФ)
МакетОбработки = ПолучитьМакет(ИмяМакета);
// Обходим массив документов, отправленных на печать (обычно там один документ)
Для Каждого СсылкаНаОбъект Из МассивОбъектов Цикл
// Очищаем номер от префиксов один раз для текущего документа
НомерДокумента = ПрефиксацияОбъектовКлиентСервер.НомерНаПечать(СсылкаНаОбъект.Номер, Истина, Истина);
// Запускаем цикл по всем получателям услуг из табличной части документа
Для Каждого СтрокаКонтрагент Из СсылкаНаОбъект.Контрагенты Цикл
// Получаем область "Шапка" из макета
ОбластьШапка = МакетОбработки.ПолучитьОбласть("Шапка");
// Заполняем параметры шапки
ОбластьШапка.Параметры.НомерДокумента = НомерДокумента;
ОбластьШапка.Параметры.ДатаДокумента = Формат(СсылкаНаОбъект.Дата, "ДФ=дд.ММ.гггг");
// Получаем представление организации (Поставщика)
СведенияОПоставщике = БухгалтерскийУчетПереопределяемый.СведенияОЮрФизЛице(СсылкаНаОбъект.Организация, СсылкаНаОбъект.Дата);
ПредставлениеПоставщика = ОбщегоНазначенияБПВызовСервера.ОписаниеОрганизации(
СведенияОПоставщике,
"НаименованиеДляПечатныхФорм,ИНН,ЮридическийАдрес,Телефоны"
);
ОбластьШапка.Параметры.ПредставлениеПоставщика = ПредставлениеПоставщика;
// Получаем представление текущего Получателя (Контрагента из строки)
СведенияОПолучателе = БухгалтерскийУчетПереопределяемый.СведенияОЮрФизЛице(СтрокаКонтрагент.Контрагент, СсылкаНаОбъект.Дата);
ПредставлениеПолучателя = ОбщегоНазначенияБПВызовСервера.ОписаниеОрганизации(
СведенияОПолучателе,
"НаименованиеДляПечатныхФорм,ИНН,ЮридическийАдрес,Телефоны,НомерСчета,Банк,БИК,КоррСчет"
);
ОбластьШапка.Параметры.ПредставлениеПолучателя = ПредставлениеПолучателя;
// Выводим заполненную шапку в итоговый табличный документ
ТабличныйДокумент.Вывести(ОбластьШапка);
// --- Здесь должен быть ваш код для вывода строк услуг и подвала ---
// Например, вывод области "Строка" и области "Подвал"
// Если в документе несколько контрагентов, каждый следующий акт печатаем с новой страницы
Если СсылкаНаОбъект.Контрагенты.Индекс(СтрокаКонтрагент) < СсылкаНаОбъект.Контрагенты.Количество() - 1 Тогда
ТабличныйДокумент.ВывестиГоризонтальныйРазделительСтраниц();
КонецЕсли;
КонецЦикла;
КонецЦикла;
// Возвращаем сформированный табличный документ на экран или принтер
Возврат ТабличныйДокумент;
КонецФункции
Представленный выше алгоритм отлично подходит для небольших документов или нечастого использования. Однако, если документ «Оказание услуг» содержит сотни или тысячи строк контрагентов, получение сведений о юрлицах (БухгалтерскийУчетПереопределяемый.СведенияОЮрФизЛице) внутри цикла может существенно замедлить работу системы. Программа будет выполнять обращение к базе данных на каждой итерации цикла.
Для оптимизации таких ресурсоемких операций рекомендуется:
Тем не менее, для первого опыта разработки внешней печатной формы базовый вариант с пошаговым циклом является наиболее понятным, наглядным и простым в отладке.
Используйте этот подход в своих разработках, и ваши печатные формы всегда будут работать без ошибок, радуя пользователей красивым и чистым оформлением!