В процессе разработки и сопровождения систем на платформе 1С:Предприятие 8 часто возникает задача выгрузки различных отчетов и печатных форм в формат Microsoft Excel. Пользователи любят этот инструмент за возможность быстрой фильтрации, сортировки, построения диаграмм и выполнения произвольных расчетов. В этой статье мы подробно и по шагам разберем, как спроектировать внешнюю печатную форму для конфигураций на базе БСП (например, Управление торговлей 11), которая будет автоматически формироваться и открываться в приложении Excel.
Мы изучим несколько альтернативных подходов — от самого простого сохранения табличного документа до гибкого управления через COM-соединение и использования макетов типа ActiveDocument. Также мы выясним, какие опасности подстерегают разработчика при работе на сервере (особенно в клиент-серверных базах под SQL) и как правильно оптимизировать код, чтобы не "повесить" рабочую базу данных.
Это самый простой, быстрый и безопасный метод выгрузки данных. Платформа 1С:Предприятие обладает встроенными механизмами конвертации собственного формата табличных документов (.mxl) в файлы Excel (.xls или .xlsx). Нам не требуется наличие установленного MS Office на компьютере или сервере, код работает кроссплатформенно и очень быстро.
Давайте разберем базовый пример реализации. Предположим, у нас уже сформирован табличный документ в переменной ТабДокумент. Наша задача — сохранить его во временный файл на диске пользователя и сразу же открыть для просмотра.
Для реализации этой логики мы можем использовать следующий код:
// Определяем путь во временном каталоге для сохранения файла
ИмяФайла = КаталогВременныхФайлов() + "ПечатнаяФорма_" + Формат(ТекущаяДата(), "ДФ=ггггММддЧЧммсс") + ".xlsx";
// Записываем табличный документ в формате XLSX
ТабДокумент.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.XLSX);
// Запускаем приложение по умолчанию для открытия полученного файла
ЗапуститьПриложение(ИмяФайла);
Этот способ прекрасно работает "из коробки", но у него есть один существенный недостаток, с которым часто сталкиваются разработчики: потеря типов данных. При стандартном экспорте числа и даты в ячейках Excel часто определяются как текстовые строки (формат "Общий"). Из-за этого пользователи не могут суммировать колонки с числами или корректно сортировать даты без ручного преобразования ячеек в самом Excel.
Выясним причину этого поведения платформы. Чтобы 1С корректно передала типы данных при конвертации в Excel, нам нужно явным образом настраивать свойства ячеек (областей) табличного документа еще на этапе его заполнения в коде. Недостаточно просто присвоить свойству Текст числовое или датированное значение.
Давайте посмотрим на пример правильного заполнения ячейки с числовым показателем:
ОбластьМакета = Макет.ПолучитьОбласть("Строка");
ЯчейкаЧисла = ОбластьМакета.Области.Сумма; // Обращаемся к конкретной именованной ячейке
// Указываем платформе, что ячейка содержит типизированное значение, а не просто текст
ЯчейкаЧисла.СодержитЗначение = Истина;
ЯчейкаЧисла.ТипЗначения = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2));
ЯчейкаЧисла.Значение = ДанныеСтроки.Сумма; // Записываем именно в свойство Значение, а не Текст
Аналогично поступаем и с датами:
ЯчейкаДаты = ОбластьМакета.Области.ДатаДокумента;
ЯчейкаДаты.СодержитЗначение = Истина;
ЯчейкаДаты.ТипЗначения = Новый ОписаниеТипов("Дата", , Новый КвалификаторыДаты(ЧастиДаты.Дата));
ЯчейкаДаты.Значение = ДанныеСтроки.Дата;
При таком подходе при выгрузке через метод Записать() Excel распознает типы данных абсолютно корректно, и пользователь сможет сразу работать с формулами.
Если вам требуется создать сложный отчет со специфическим форматированием, условным выделением ячеек, автофильтрами, группировками или формулами самого Excel, стандартного экспорта MXL может не хватить. В этом случае мы можем прибегнуть к технологии COM-соединения и управлять приложением Excel напрямую из кода 1С.
Проанализируем классический пример работы с COM-объектом:
&НаКлиенте
Процедура ВыгрузитьЧерезCOM(ТаблицаДанных)
// Создаем экземпляр приложения Excel на стороне клиента
Попытка
Excel = Новый COMОбъект("Excel.Application");
Исключение
Предупреждение("Не удалось запустить Microsoft Excel. Возможно, приложение не установлено.");
Возврат;
КонецПопытки;
// Делаем окно приложения невидимым на время заполнения для ускорения работы
Excel.Visible = Ложь;
// Добавляем новую рабочую книгу
Книга = Excel.Workbooks.Add();
Лист = Книга.Sheets(1);
// Заполняем шапку таблицы
Лист.Cells(1, 1).Value = "Номер";
Лист.Cells(1, 2).Value = "Контрагент";
Лист.Cells(1, 3).Value = "Сумма";
// Применяем простейшее форматирование к шапке
Шапка = Лист.Range(Лист.Cells(1, 1), Лист.Cells(1, 3));
Шапка.Font.Bold = Истина;
Шапка.Interior.ColorIndex = 15; // Серый цвет фона
НомерСтроки = 2;
Для Каждого СтрокаДанных Из ТаблицаДанных Цикл
Лист.Cells(НомерСтроки, 1).Value = СтрокаДанных.Номер;
Лист.Cells(НомерСтроки, 2).Value = СтрокаДанных.Контрагент;
Лист.Cells(НомерСтроки, 3).Value = СтрокаДанных.Сумма;
НомерСтроки = НомерСтроки + 1;
КонецЦикла;
// Автоматически подбираем ширину колонок под содержимое
Лист.Columns("A:C").AutoFit();
// Делаем Excel видимым для пользователя
Excel.Visible = Истина;
КонецПроцедуры
Важное предостережение! Обратите внимание на директиву компиляции &НаКлиенте в примере выше. Создание COM-объектов на стороне сервера в клиент-серверных базах данных (особенно под управлением MS SQL или PostgreSQL на серверных ОС) сопряжено с колоссальными рисками:
EXCEL.EXE останется висеть в памяти операционной системы сервера. При частых запусках десятки таких процессов способны полностью заблокировать оперативную память и процессорные мощности сервера, парализовав работу всей компании.USR1CV8), которая по умолчанию не имеет прав на запуск интерактивных приложений через DCOM. Это приводит к труднодиагностируемым ошибкам при попытке инициализации объекта.Поэтому золотое правило разработчика 1С гласит: любая работа с COM-объектами офисных приложений должна происходить исключительно на стороне клиента! Если вам нужно подготовить данные на сервере, соберите их во временную таблицу значений или массив структур, передайте этот пакет данных на клиент, и уже на клиенте инициализируйте COM-объект Excel и заполняйте его.
Если вы хотите получить идеально оформленный документ, но не желаете писать сотни строк монотонного кода для настройки шрифтов, границ и цветов ячеек через COM, отличным решением станет использование макета типа ActiveDocument.
Рассмотрим этот подход по шагам:
=СУММ(C3:C100)), задайте стили шрифтов.Чтобы программно заполнить этот шаблон данными и вывести его пользователю, мы используем следующий алгоритм:
&НаКлиенте
Процедура ПечатьАктивногоДокумента()
// Получаем макет обработки. Т.к. получение макета возможно только на сервере,
// предварительно сохраняем макет во временный файл и передаем на клиент.
ПутьКШаблону = ПолучитьПутьКШаблонуНаСервере();
Попытка
ExcelApp = Новый COMОбъект("Excel.Application");
Книга = ExcelApp.Workbooks.Open(ПутьКШаблону);
Лист = Книга.Sheets(1);
Исключение
Сообщить("Ошибка инициализации Excel: " + ОписаниеОшибки());
Возврат;
КонецПопытки;
// Заполняем ячейки шаблона конкретными значениями
Лист.Cells(3, 2).Value = "ООО 'Рога и Копыта'"; // Заполняем покупателя
Лист.Cells(4, 2).Value = ТекущаяДата(); // Заполняем дату
// Отображаем заполненный шаблон пользователю
ExcelApp.Visible = Истина;
// Важно: не вызываем метод Quit(), чтобы документ остался открытым для работы
КонецПроцедуры
Обратите внимание на важный нюанс работы с ActiveDocument: если переменная ExcelApp объявлена локально внутри процедуры, то при завершении работы этой процедуры переменная будет уничтожена сборщиком мусора 1С, что приведет к мгновенному автоматическому закрытию окна Excel. Чтобы этого не происходило, делайте переменную ExcelApp глобальной переменной модуля формы или модуля объекта печатной формы, либо сохраняйте заполненный файл на диск и открывайте его через ЗапуститьПриложение(), предварительно закрыв COM-соединение.
В современных реалиях импортозамещения и активного переноса серверов 1С на операционную систему Linux использование COM-технологий уходит в прошлое. На смену им приходит генерация файлов формата OpenXML (стандартный формат файлов .xlsx).
Файл XLSX представляет собой обычный ZIP-архив, внутри которого упакованы файлы разметки XML. Мы можем формировать структуру этих файлов программно прямо в коде 1С, используя стандартные объекты работы с ZIP-архивами и текстом XML. Однако писать такой код с нуля — задача колоссальной сложности.
Для решения этой проблемы в сообществе разработчиков 1С созданы готовые открытые библиотеки (классы) на чистом коде 1С, которые позволяют генерировать файлы Excel напрямую. Они работают без вызова внешних программ, со скоростью, превышающей работу через COM-объект в десятки раз, и абсолютно безопасно функционируют на серверах под управлением Linux.
Основные преимущества использования OpenXML:
Если мы разрабатываем внешнюю печатную форму для типовой конфигурации (например, 1С:Управление торговлей 11), то она обязательно должна подключаться через стандартный механизм дополнительных отчетов и обработок БСП. Для быстрого поиска функций и приемов работы с библиотекой пригодится инструмент для изучения методов БСП.
При использовании подсистемы "Печать" БСП нам не нужно самостоятельно придумывать велосипеды с ручным сохранением файлов на диск и вызовом внешних приложений. БСП уже содержит великолепную форму предварительного просмотра табличных документов, которая предоставляет пользователю готовые инструменты для сохранения файла в любом удобном формате (включая Excel, PDF, Word) и отправки его по электронной почте.
Чтобы печатная форма корректно зарегистрировалась в системе, в модуле объекта внешней обработки мы должны описать обязательную экспортную функцию СведенияОВнешнейОбработке():
Функция СведенияОВнешнейОбработке() Экспорт
ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработке("2.2.2.1");
ПараметрыРегистрации.Вид = ДополнительныеОтчетыИОбработкиКлиентСервер.ВидОбработкиПечатнаяФорма();
ПараметрыРегистрации.Версия = "1.0";
ПараметрыРегистрации.Наименование = "Реализация товаров в формате Excel (внешняя)";
ПараметрыРегистрации.БезопасныйРежим = Ложь;
// Указываем объекты, к которым подключается печатная форма
ПараметрыРегистрации.Назначение.Добавить("Документ.РеализацияТоваровУслуг");
// Описываем команду печати
НоваяКоманда = ПараметрыРегистрации.Команды.Добавить();
НоваяКоманда.Представление = "Выгрузить в Excel...";
НоваяКоманда.Идентификатор = "ВыгрузкаExcel";
НоваяКоманда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипВызоваВызовСерверногоМетода();
НоваяКоманда.Модификатор = "ПечатьMXL"; // Указываем БСП, что мы возвращаем табличный документ
Возврат ПараметрыРегистрации;
КонецФункции
В этом случае в процедуре Печать() мы просто формируем красивый, правильно типизированный табличный документ ТабДокумент (как мы научились в Способе 1) и возвращаем его в БСП. Платформа сама покажет его пользователю, а стандартные кнопки БСП позволят сохранить его в идеальный Excel-файл в одно нажатие кнопки мыши. Это наиболее профессиональный, надежный и поддерживаемый путь разработки внешних печатных форм в среде 1С:Предприятие 8.