При разработке печатных форм в среде 1С:Предприятие 8.3 мы часто используем метод ПроверитьВывод() объекта ТабличныйДокумент. Этот инструмент позволяет динамически определять, помещается ли область на текущую страницу, и вовремя вставлять разделители. Однако в клиент-серверном режиме, особенно при использовании операционных систем семейства Linux (например, Astra Linux), программисты сталкиваются с критической ошибкой: метод всегда возвращает Истина, что приводит к бесконечному циклу формирования документа. В этой статье мы подробно разберем причины этой проблемы и рассмотрим несколько эффективных способов ее решения.
Для начала разберем, как именно 1С «понимает», помещается ли текст на страницу. Метод ПроверитьВывод() не просто считает строки, он обращается к метрикам шрифтов и параметрам текущего принтера, установленного в системе. В среде Linux, если сервер 1С запущен под пользователем usr1cv8, возникают следующие сложности:
usr1cv8 не выбран принтер по умолчанию, движок 1С не может получить физические границы страницы. В этом случае высота страницы может инициализироваться как «бесконечная».Xvfb расчет графических областей может выполняться некорректно.В результате метод ПроверитьВывод() считает, что места на листе бесконечно много, и цикл Пока ТабДок.ПроверитьВывод(Область) Цикл никогда не завершается, вызывая зависание рабочего процесса сервера — для принудительного прерывания таких процессов есть утилита администрирования серверов 1С для завершения зависших сеансов.
Прежде чем менять программный код, нам необходимо убедиться, что серверная среда подготовлена к расчету печатных форм. Разберем необходимые шаги по настройке.
Шаг 1. Настройка службы CUPS. Убедимся, что на сервере установлен пакет cups. Нам необходимо создать виртуальный принтер (PDF-принтер) и назначить его принтером по умолчанию для пользователя 1С. Проверим статус принтеров командой в консоли сервера:
sudo -u usr1cv8 lpstat -d
Если система отвечает, что назначение по умолчанию отсутствует, необходимо его установить. Также в Astra Linux SE проверьте файл /etc/cups/cupsd.conf — опция MacEnable должна быть включена, а пользователь usr1cv8 должен входить в группу lp.
Шаг 2. Установка шрифтов. 1С требует наличия стандартных шрифтов Microsoft (Arial, Times New Roman) для расчета высоты строк. Установим их:
sudo apt-get install ttf-mscorefonts-installer
Шаг 3. Использование Xvfb. Для корректной работы графических методов на «безголовом» сервере рекомендуется запуск 1С с использованием Xvfb (X virtual framebuffer). Это создаст виртуальный экран, к которому 1С сможет обращаться за метриками графических объектов.
Часто метод ПроверитьВывод() дает сбой, потому что в объекте ТабличныйДокумент не заданы жесткие рамки. Давайте посмотрим, как правильно инициализировать документ перед началом вывода областей. Проанализируем пример кода:
ТабДок = Новый ТабличныйДокумент;
ТабДок.ОриентацияСтраницы = ОриентацияСтраницы.Ландшафт;
ТабДок.РазмерСтраницы = "A4";
ТабДок.АвтоМасштаб = Истина;
// Важно задать имя принтера, даже если он виртуальный
ТабДок.ИмяПринтера = "PDF";
Важный нюанс: Не устанавливайте КлючПараметровПечати в самом начале цикла. Если система найдет сохраненные ранее некорректные настройки принтера, они могут перебить программные установки и снова привести к зависанию.
Если системные настройки Linux не помогают, мы можем применить альтернативный подход. Вместо метода ПроверитьВывод(), который проверяет «возможность» вывода, мы будем использовать метод КоличествоСтраниц(), который анализирует уже сформированный документ. Рассмотрим этот способ подробнее:
// Создаем вспомогательный документ для проверки
ТабДок = Новый ТабличныйДокумент;
ТекСтраниц = ТабДок.КоличествоСтраниц();
Пока Выборка.Следующий() Цикл
// Сначала пробуем вывести в основной документ
ТабДок.Вывести(ОбластьСтроки);
// Если количество страниц увеличилось — значит, произошел перенос
Если ТабДок.КоличествоСтраниц() > ТекСтраниц Тогда
// Удаляем последнюю выведенную строку (она ушла на новую страницу)
// И выводим её заново, но уже после разделителя или шапки
// (Логика может варьироваться в зависимости от задачи)
ТабДок.ВывестиГоризонтальныйРазделительСтраниц();
ТекСтраниц = ТабДок.КоличествоСтраниц();
КонецЕсли;
КонецЦикла;
Внимание: Метод КоличествоСтраниц() работает значительно медленнее, чем ПроверитьВывод(), так как каждый раз заставляет сервер пересчитывать всю геометрию документа. Используйте этот метод только для небольших отчетов.
Для предотвращения «мертвого» зависания рабочего процесса 1С, мы настоятельно рекомендуем всегда добавлять в циклы с ПроверитьВывод() ограничение по количеству итераций. Это позволит программе выдать ошибку вместо бесконечного потребления ресурсов сервера. Разберем пример безопасного цикла:
ТабДок.Вывести(ОбластьШапка);
МаксимальноеКоличествоСтрок = 1000; // Разумный предел для одной страницы
ВыведеноНаСтраницу = 0;
Пока Выборка.Следующий() Цикл
ОбластьДляВывода = ПолучитьОбластьСтроки(Выборка);
// Проверяем вывод с дополнительным счетчиком-предохранителем
Если НЕ ТабДок.ПроверитьВывод(ОбластьДляВывода) ИЛИ (ВыведеноНаСтраницу > МаксимальноеКоличествоСтрок) Тогда
ТабДок.ВывестиГоризонтальныйРазделительСтраниц();
ВыведеноНаСтраницу = 0;
КонецЕсли;
ТабДок.Вывести(ОбластьДляВывода);
ВыведеноНаСтраницу = ВыведеноНаСтраницу + 1;
КонецЦикла;
В данном примере, даже если ПроверитьВывод() вернет неверное значение Истина, наш счетчик ВыведеноНаСтраницу принудительно разорвет бесконечный цикл и вставит разделитель, когда количество строк превысит 1000. Это спасет сервер от падения.
Проблема бесконечного цикла ПроверитьВывод() в Linux — это комплексная ошибка, связанная с тем, что серверный процесс 1С оказывается в изолированной среде без доступа к подсистеме печати. Для стабильной работы мы рекомендуем:
usr1cv8 через lpstat.msttcorefonts.ПроверитьВывод() на упрощенный постраничный подсчет строк или использование КоличествоСтраниц().Следуя этим шагам, мы обеспечим отказоустойчивость системы и корректное формирование печатных форм независимо от используемой операционной системы.