Настройка pdf в 1с
На одном из крупных проектов возникла не совсем обычная для 1С задача. Нужно было организовать массовую отправку и подписание документов контрагентов с помощью электронной цифровой подписи. Поиск информации в справочной системе и на 1Сных форумах нужного результата не дал. Пришлось разбираться со средствами криптографии, электронными ключами и сторонними утилитами. Найденное решение оказалось простым и достаточно гибки для повторения в других проектах, поэтому хочу с вами поделиться.
Постановка задачи в цифрах:
• На предприятии заказчика работает почти 3000 человек в более 50 филиалах по всей России.
• На предприятии заказчика используется УПП 1.3 (платформа 8.2.19.76).
• Более 10 000 активных контрагентов.
• Для большей части контрагентов (покупателей) раз в месяц нужно отправлять документы в электронном виде (Счета, акты, счета-фактуры, РТУ и т.д.). Всего, около 100 000 документов.
• На отправку документов выделяется 2 рабочих дня.
• В процедуре отправки должно быть задействовано минимальное количество людей. Сейчас их число удалось сократить до 2х человек.
• Документы должны отправляться по электронной почте в виде вложенных PDF-файлов. Каждый PDF-файл должен быть подписан ЭЦП.
Два слова, что вообще собой представляет ЭЦП. Для подписания и работы с файлами используется два ключа: закрытый и открытый. Закрытый ключ хранится у Вас на токене и используется для подписания или шифрования документов. Открытый ключ должен быть распространен всем пользователям, которые должны работать с подписанным Вами документом. Обычно это происходит автоматически при подписании файла. Далее, есть файл, который нам нужно подписать. С помощью специального ПО из содержания файла и Вашего закрытого ключа создается уникальная символьная последовательность, что-то вроде контрольной суммы. Эта последовательность и есть электронно-цифровая подпись. ЭЦП всегда уникальна для данного пользователя и данного документа. Подпись содержит информацию о дате подписания документа, подписанте, контрольную сумму для подписанного документа и ссылку или сам файл открытого ключа. Подпись может быть добавлена в подписываемый файл или сохранена в виде отдельного файла. Нас, конечно, интересует первый вариант.
Решение первое, полу-ручное
Подавляющее большинство ключей ЭЦП выпускаются в виде eToken или Rutoken USB-модулей. В моем случае был eToken. Кто не знает, основное отличие состоит в том, что eToken имеет встроенный аппаратный криптографический сопроцессор. Это значит, что при шифровании данных закрытый ключ не покидает токена. В нашем случае эта разница значения не имеет.
Не буду рассматривать установку драйверов USB-ключей. Они, как правило, поставляются выпускающим удостоверяющим центром вместе с самими токенами и установка проблем не вызывает. Еще с токенами обычно поставляется лицензия на КРИПТО-ПРО и утилита КриптоПро CSP. Я использовал последнюю доступную на данный момент версию 3.9.
Дальше все просто. Запускаем КриптоПро CSP. Закладка Сервис, кнопка Посмотреть сертификаты в контейнере, нажимаем Обзор для выбора токена с криптохранилищем, и выбираем нужно нам хранилице. Обычно на одном токене одно хранилище.
Нажимаем Далее и получаем окошко с информацией по сертификату, к которому привязан ключ. Ждем кнопку Установить и устанавливаем сертификат в хранилище Личное для локального пользователя. Обычно, вместе с утилитой КриптоПро CSP в меню Пуск устанавливается ярлык для оснастки Сертификаты. Запускаем оснастку, убеждаемся, что все правильно сделано и сертификат действительно установился в раздел Личное для текущего пользователя.
Дальше, Кликаем правой кнопкой по установленному сертификату, Все задачи, Экспорт. Обязательно отказываемся экспортировать закрытый ключ и сохраняем сертификат куда-нибудь на локальный компьютер, например, на рабочий стол, в формате файла X.509 (.CER) в кодировке DER. Сохраненный сертификат нам понадобиться дальше для выполнения подписи.
Работа утилиты крайне проста. Выбираем папку в которой находятся PDF-файлы, выбираем папку в которую будут сохранены файлы с подписью (если это одна и так же папка, в дополнительных настройках нужно установить флажок «Перезаписывать файлы с одинаковыми именами») выбираем из контейнера сертификат, который будем использовать для подписи, вводим пин от ключа и, если все указали правильно, через несколько секунд в папке-приемнике появятся подписанные PDF-файлы. Для того, чтоб ЭЦП признавалась юридически, по закону, должна быть установлена еще метка времени, но мне для задачи это не требовалось.
В принципе, все! Если у Вас небольшая организация и пара десятков контрагентов то можно вообще ничего больше не делать и оставить все в ручном режиме. Кроме того, 1С нам пока вообще не была нужна, документы в формате PDF можно создать многими способами, в том числе и из Microsoft Office.
Долго не мог разобраться, почему подпись не проходит и выдает ошибку. Оказалось, что успешной работы утилиты КриптоПро PDF на компьютере должна быть установлен Adobe Acrobat Pro (не Reader, это важно!). Именно с его помощью утилита модифицирует PDF-файлы и добавляет и них подпись.
Пример подписанного файла на картинке. Выглядит как обычный PDF, только на закладке Подписи появились данные о подписанте. Из важного, указано кто подписал документы (обычно это ФИО и название организации) и что с момента подписания документ не изменялся. Информацию о том, что сертификат ненадежный можно игнорировать. Это говорит только о том, что компания Adobe и ее продукт Acrobat Reader ничего не знают о Вашем сертификате.
Решение второе, автоматическое
Обработка уже умеет печатать отобранные документы. В последних версиях платформы появился штатный механизм сохранения печатных форм в виде PDF файлов. Осталось совместить эти два механизма и сохранять выбранные пользователем документы в папку на локальном компьютере, а затем запускать командную строку и запускать утилиту КриптоПро PDF для выполнения подписи.
Немного доработали интерфейсную часть. Убрали из обработки работу со справочниками. Оставили в интерфейсе 4 вида документов, которые нужно отправлять. Изменили систему отборов. Создали новый регистр сведений Настройки ЭЦП. В него для каждого пользователя сохраняется информация о том, по какому пути лежит КриптоПро PDF на локальном компьютере, папки для временного хранения файлов, сертификат, которым будет выполнена подпись. Еще просили сохранять пин от ключа, но мы не стали этого делать из соображений безопасности.
Чтоб автоматизация была уж совсем полной, пришлось в 1С оживить модуль электронной почты. Дальше все просто. Раз в месяц оператор выбирает список контрагентов и виды документов, которые должны быть отправлены, проверяет результат отбора, нажимает кнопку Выполнить, вводит пин-код от ключа и ждет… В моем случае формирование пакета документов может длится несколько часов.
Обработка группирует отобранные документы по контрагентам, дальше циклом проходится по каждому контрагенту, выбирает все его документы, сохраняет в виде PDF-файлов на диск, запускает утилиту КриптоПро PDF из командной строки, подписывает сохраненные документы, создает документ Электронное письмо с контактными данными из справочника контрагентов, в качестве вложения прикрепляет подписанные документы из папки на диске, переводит письмо в статус для отправки и переходит к следующему контрагенту. Письма отправляются регламентным заданием раз в 10 минут. Обработку можно оставлять на ночь. Возникшие проблему будут корректно обработаны, а утром пользователь увидит журнал шибок и журнал отправленных писем.
Для удобства приведу кусочек кода, который выполняет саму процедуру подписания. Все параметры берутся из созданного регистра сведений.
Всем привет. Как-то мне поступило задание прикреплять PDF файлы к документам в 1С, при том что было много документов и один многостраничный PDF файл, который необходимо было разделять на странички и каждая страница соответствовала определенному документу. Естественно мне хотелось автоматизировать полностью весь процесс, чтобы 1с сама разделяла файл PDF на листы, прочитывала каждый лист и сопоставляла его с документом. Я нашла решение и прикрепляю программы, которые мне в этом помогли:)
Программа Pdftk server позволила мне узнать сколько страниц есть в файле PDF:
Далее программа Pdftk server при помощи команды "cat + "номер страницы" + output" разбила мне файл PDF по страницам в цикле:
В итоге у меня в папке есть много файлов PDF по одной страничке, теперь мне необходимо прочитать каждый файл при помощи программы PDF2TXT:
Вот ссылки на программы:
Мы создали текстовый файл в кодировке UTF-8, теперь его нужно прочитать:
Вот где я скачала программу-помощницу:
Инструменты XPDF (по ссылке скачать инструменты xpdf, в архиве найдете pdftotext, остальные файлы не нужны)
Надеюсь, моя работа поможет многим!)
Специальные предложения
(0) (1) Можно воспользоваться tesseract ocr (смотрите на github'е)
Там крайне много возможностей, в том числе можно получать не только сырой текст, но и положение онного на странице.
Ставиться не сложно, на лине так вообще одной строкой в терминале.
Под винду уже есть собраные версии.
(1)Наше то,. что долго искал.
Есть вопрос - попробовал использовать закомментированный кусок кода:
Платформа благополучно отъезжает.
На сохранении файла - работает корректно все.
Этот метод работает?
Я в свое время тоже разбирался с разбиением ПДФов. Мне понравилась программа GostScript, в ней разбиение многостраничного файла делается одной командой: вот строка из bat-файла
call "C:\Program Files\gs\gs9.20\bin\gswin64.exe" -q -dSAFER -dBATCH -dNOPAUSE -sDEVICE=jpeg -r100 -sPAPERSIZE=a4 -sOutputFile="Z:\!\doc-%03d.jpg" "Z:\!\1234.pdf"
Здесь:
"Z:\!\1234.pdf" - путь к многостраничному фалу
-sOutputFile="Z:\!\doc-%03d.jpg" - параметр говорит о создании файлов по маске (1 страница - 1 файл): doc-001.jpg, doc-002.jpg, doc-003.jpg, .
В свое время остановился, на попытке понять как обработать не 1, 2, 3 многостраничный файлов, а 100+ (так до конца и не разобрался с параметрами). Может время придет - вернусь к работе
Без компонент, на двоичных данных бы. За такое и 10 $m не жалко будет!Где-то на ИС встречал в комментариях "Количество страниц в PDF-файле". (6) интересно. хотелось бы, а то этот конвертер PDF2TXT на 30 дней, еще ключи искать, бесплатную прогу найти пока не смогла
(7) Можно воспользоваться tesseract ocr (смотрите на github'е)
Там крайне много возможностей, в том числе можно получать не только сырой текст, но и положение онного на странице.
Ставиться не сложно, на лине так вообще одной строкой в терминале.
Под винду уже есть собраные версии.
UPD:
Если вопрос стоит как "искать ключи", то очивидный FineReader очивиден, дальше торрентов искать не придеться ;-)
Также практически на 100% уверен, что у гугла есть подобный вебсервис, там вроде хотели денюжек, но крайне мало и возможно есть "триал".
(27) посмотрите я дополнила статью, нашла бесплатное приложение pdftotext, работает тоже из командной строки :)Для ковыряния двоичных данных под окнами лучше использовать бесплатный HxD
(6) (7) Из личного: для решения описанной задачи (0) мы сначала воспользовались программой ABBYY Scan Station (ABBYY - по запросу спокойно предоставляет 30-дневный ключ, спокойно предоставили продление еще на 1 месяц, для тестов), после чего мы сделали приобретение, т.к. софтина ОЧЕНЬ проста в настройке и хорошо выполняет обозначенную задачу (но без распознавания).
Единственный ее недостаток и весьма значительный - это не возможность ее запустить с командной строки - то есть нет запуска по расписанию.
Но из плюсов я бы назвал цену 2-3 года назад она составляла 24 000 руб. или 10 часов франча (на тот момент).
Так мы поигрались наверное с год, пока мне не надоело запускать каждый день данную сфотину и мы приобрели ее расширенную версию - ABBYY Recognation Server. В данной софтине настроек и возможностей поболее - работает на УРА уже 1,5 года. Есть еще распознавание и индексирование - последнее требует работу оператора (при приобретении удалось зачесть стоимость ранее приобретенной ABBYY Scan Station).
По ценам уже значительно дороже и цена зависит от количества распознанных страниц в месяц. На сегодня у нас 50к страниц и этого пока хватает (1 числа каждого месяца счетчик сбрасывается).
Цены опять же в открытых источниках не найти, но я их так же приведу для понимания: Сама программа + лицензия на 15к страниц - 215 000 руб, апгрейд с 15к до 50к страниц- 170к руб, апгрейд с 15к до 100к страниц - 247к руб (цены на июль 2016)
Стоимость разовая и в дальнейшем доплат не требует.
Это не реклама , просто показал, что решили использовать у нас в организации. Иногда может быть значительно эффективнее купить готовый продукт, чем писать свое с нуля. С нуля для разработчика хорошо - ты учишься работать с "новым", но работодатель не всегда может быть заинтересован оплачивать таким образом твое обучение, если стоит вопрос в сроках и качестве (ведь сколько еще времени уйдет на отладку "подводных камней").
Возникла задача (и, как показал поиск, не у меня одного) формирования печатных форм в формате pdf для отправки клиентам. Причем процесс этот должен был происходить практически полностью автоматически - в один-два клика. То, что я нашел на эту тему в сети меня не устроило по тем или иным причинам, поэтому пришлось писать свое. Первое с чем я столкнулся - это достаточно скудное количество информации на эту тему, очень мало примеров. Несколько дней разбирался сам, теперь решил поделиться опытом с вами. Америку, я конечно не открыл, но пару интересных решений в процессе написания родилось - возможно кому-то пригодится и сэкономит время.
Публикацию я решил оформить в виде статьи, поскольку написанная мной обработка имеет несколько прикладной характер и заточена под конкретную конфигурацию. Так что поделюсь с вами кодом, и постараюсь прокомментировать его максимально подробно.
Итак, сначала немного предыстории. Изучив вопрос, я остановил свой выбор на бесплатных виртуальных принтерах BullZip PDF Printer и PDFCreator, которые позволяют на выходе получать файлы pdf, а также файлы различных графических форматов. Обе утилиты имеют возможность автосохранения файлов без лишних вопросов пользователю. В принципе, для полуавтоматического создания печатных форм в электронном виде, этого достаточно. Мы можем написать в коде
ТабДок . ИмяПринтера = "PDFCreator" ; //"BullZip PDF Printer";
ТабДок . Напечатать ();
и в каталогах, указанных в настройках автосохранения, появятся нужные файлы. Но, во-первых, пользователь может что-нибудь в настройках изменить, во-вторых, принтер вообще может оказаться переименован или удален чьими-нибудь шаловливыми ручонками (то есть нам нужно как-то контролировать имя и вообще наличие виртуального принтера в системе), в-третьих, придется настроить автосохранение для каждого пользователя (если принтер не сетевой), в-четвертых, проблематично добиться вменяемого имени файла с помощью настроек. Да и вообще, мы же все хотим делать автоматически, а так пользователю придется самому создать письмо, указать адрес клиента, прикрепить нужные вложения - вероятность ошибки возрастает, ну и лениво конечно. Приходим к выводу, что нужно юзать COM-объект, самому устанавливать необходимые настройки и выполнять нужные действия, чтобы не взрывать потом мозг ни себе, ни пользователю.
Изначально имелось пожелание сохранять файлы в графическом формате, скажем jpeg или png. PDFCreator, по-моему мнению, обладает более гибкими возможностями, но, к сожалению, он не умеет разбивать изображения на страницы, поэтому при сохранении печатных форм в виде картинок, можно наблюдать только первую страницу документа. BullZip же такую функцию имеет, поэтому я начал работать с ним. Но вот его COM-интерфейс оказался довольно скудным, да и плюс ко всему, настройки свои утилита хранит в ini-файле. Соответственно тратится время на их чтение и запись, если мы хотим (а мы хотим!) в них что-то менять. Вобщем, чтобы не извращаться и не придумывать всякую ерунду, было принято решение сохранять печатные формы в pdf и использовать для этих целей PDFCreator. Полностью конечно "ерунды" избежать не удалось, но в целом задача была решена.
Собственно дальше код моей функции для формирования файлов с подробными комментариями в проблемных местах. Функция выдрана из модуля обработки с минимальными изменениями, поэтому имеет "узкие" места в виде привязки к конфигурации и конкретному виду документов. Но общий смысл понятен и при необходимости код легко может быть преобразован для конкретной задачи.
upd 14.04.2011
Сегодня понадобилось переписать обработку, сделав ее более универсальной. Теперь в главную функцию передается массив готовых табличных документов для конвертации в pdf. Для передачи имен файлов используется свойство табличного документа "ИспользуемоеИмяФайла", которое необходимо заполнить программно до вызова функции конвертации.
upd 03.05.2011
Выявил неявный баг. У табличного документа есть свойство "ИмяПараметровПечати". Оно отвечает за сохранение параметров печати, установленных пользователем, и их восстановление при следующем показе табличного документа. Так вот, если это свойство используется в конфигурации (а в типовых оно, как правило, используется), то при печати в pdf в указанных параметрах будет сохранен наш виртуальный pdf-принтер, и, если в следующий раз табличный документ будет печататься обычным способом, то 1С восстановит именно этот принтер для печати по-умолчанию (не путать с принтером по-умолчанию в Windows). Чтобы этого избежать, после формирования наших файлов, вернем табличному документу его старое имя принтера.
// Функция формирует файлы для отправки по электронной почте с помощью виртуального принтера PDFCreator,
// Возвращаемое значение: тип "Массив" - массив сформированных файлов pdf
// Параметры: ТабличныеДокументы - тип "Массив", массив табличных документов для конвертации
// Путь - тип "Строка", путь к каталогу, в котором будут создаваться конечные файлы pdf
//
Функция PDFCreator_СформироватьФайлыДляОтправки ( ТабличныеДокументы , Путь ) Экспорт
Состояние ( "Настройка виртуального принтера . " );
// Получим виртуальные принтеры, установленные в системе, если нет ни одного - создадим новый, если есть - будем использовать первый попавшийся
ПринтерыPDF = УтилитаПечати . cGetPDFCreatorPrinters ();
Если ПринтерыPDF . Count () = 0 Тогда
УтилитаПечати . cAddPDFCreatorPrinter ( "PDFCreator" );
ПринтерыPDF = УтилитаПечати . cGetPDFCreatorPrinters ();
КонецЕсли;
ИмяПринтераPDF = ПринтерыPDF . Item ( 1 );
// Запустим утилиту, в области уведомлений появится соответствующий значок очереди печати
УтилитаПечати . cStart ();
// PDFCreator позволяет создавать несколько профилей с настройками - это очень удобно: мы не будем менять настройки по умолчанию, а создадим отдельный профиль для печати из 1С и будем его использовать. То есть для "ручной" печати пользователь может настроить принтер как ему вздумается.
// Проверим, существует ли профиль для печати документов из 1С, если нет - создадим
Если Не УтилитаПечати . cProfileExists ( "Печать 1С" ) Тогда
УтилитаПечати . cAddProfile ( "Печать 1С" , УтилитаПечати . cStandardOptions );
КонецЕсли;
// Поскольку теоретически пользователь может изменить настройки и нашего профиля, а некоторые из них для нас критичны, будем записывать их принудительно каждый раз. Это настройки автосохранения, остальные - пусть меняет, если надо.
// Запишем настройки профиля, которые не должны меняться
НастройкиПоУмолчанию = УтилитаПечати . cReadOptions ( "Печать 1С" );
НастройкиПоУмолчанию . UseAutosave = 1 ;
НастройкиПоУмолчанию . UseAutosaveDirectory = 1 ;
НастройкиПоУмолчанию . UseCreationDateNow = 1 ;
НастройкиПоУмолчанию . AutosaveDirectory = Путь ;
// Подробно на каждой опции останавливаться не буду, думаю и так понятно. Поясню только принципиальный момент, на котором строится дальнейшая логика работы функции.
// Я долго пытался добиться более менее вменяемого и при этом уникального имени файла стандартными настройками - это оказалось довольно проблематично. В итоге я пришел к такой схеме: в качестве имени файла автосохранения используем предопределенную настройку Title - заголовок нашего документа. Поскольку табличный документ мы создаем программно, средствами 1С изменить его не удастся (есть лишь возможность задать его при выводе на экран, указав в качестве первого параметра метода Показать()). Соответственно, используя такую настройку, мы всегда будем получать файл вида "Табличный документ.pdf". Что ж, значит, придется переименовать его после. Если бы мы печатали один файл, можно было задать его имя сразу в настройках, но мы-то хотим печатать много и сразу, а в этом случае опции просто не будут успевать сохраняться. Короче говоря, экспериментальным путем я пришел именно к такому варианту.
НастройкиПоУмолчанию . AutosaveFileName = "Title" ; // Здесь Title должно быть в угловых скобках, но редактор HTML воспринимает это как тег и сбивает разметку
НастройкиПоУмолчанию . AutosaveFormat = 0 ; // 0 = PDF, 1 = PNG, 2 = JPEG, 3 = BMP, 4 = PCX, 5 = TIFF, 6 = PS, 7 = EPS, 8 = TXT, 9 = PDF/A-1b, 10 = PDF/X, 11 = PSD, 12 = PCL, 13 = RAW
НастройкиПоУмолчанию . AutosaveStartStandardProgram = 0 ;
УтилитаПечати . cSaveOptions ( НастройкиПоУмолчанию , "Печать 1С" );
Состояние ( "Создание файлов . " );
// Делаем наши настройки текущими. Возможно как-то можно сделать активным конкретный профиль программно, но мне это не удалось, а так - заработало и ладно. По сути здесь мы подменяем настройки по умолчанию своими.
УтилитаПечати . cOptionsProfile = "Печать 1С" ; // эта строка, по-моему, не работает, но так "красивше" =)
УтилитаПечати . cOptions = НастройкиПоУмолчанию ;
// Собственно, начинаем штамповать наши файлы
МассивФайлов = Новый Массив ;
Для Индекс = 0 По ТабличныеДокументы . Количество () - 1 Цикл
// Получаем табличный документ по индексу из массива. Цикл Для . По . используем для того, чтобы иметь возможность сразу получать индекс элемента из счетчика без применения метода Найти().
ТабДок = ТабличныеДокументы [ Индекс ];
// Запоминаем старое имя принтера, т.к. при использовании параметров печати, они будут сохраняться с нашим pdf-принтером
СтароеИмяПринтера = ТабДок . ИмяПринтера ;
// Далее уже знакомый нам кусок кода. Все настройки сделаны - можем смело печатать.
ТабДок . ИмяПринтера = ИмяПринтераPDF ;
ТабДок . Напечатать ();
// Здесь одна особенность, которую я победил не очень хорошим способом. Помните, что у нас все файлы называются "Табличный документ.pdf"? Это нас не устраивает - надо переименовать, но поскольку принтер работает не мгновенно, необходимо сначала дождаться, пока файл сформируется и запишется на диск. Так что запускаем цикл и ждем пока файл появится. Да, грузится проц, но что поделать - это ненадолго.
// На случай, если что-то пойдет не так, ставим ограничение в 30 секунд, по истечении которых цикл прерываем принудительно
ФайлСформирован = Истина;
ФайлPDF = Новый Файл ( Путь + "Табличный документ.pdf" );
Порог = ТекущаяДата () + 30 ;
Пока Не ФайлPDF . Существует () И ФайлСформирован Цикл
ОбработкаПрерыванияПользователя ();
Если ТекущаяДата () >= Порог Тогда
ФайлСформирован = Ложь;
КонецЕсли;
КонецЦикла;
// Наш файл уже существует, но еще не записан - ждем еще, но не более 30 секунд
Порог = ТекущаяДата () + 30 ;
Пока ФайлPDF . Размер () = 0 И ФайлСформирован Цикл
ОбработкаПрерыванияПользователя ();
Если ТекущаяДата () >= Порог Тогда
ФайлСформирован = Ложь;
КонецЕсли;
КонецЦикла;
Возврат Неопределено;
КонецЕсли;
// Вот теперь переименуем его. Используем свойство табличного документа "ИспользуемоеИмяФайла" (должно быть заполнено программно до вызова процедуры, предполагается, что имя файла указано без расширения), либо , если оно не заполнено , просто порядковый номер элемента.
НовоеПолноеИмя = Путь + ?( ЗначениеЗаполнено ( ТабДок . ИспользуемоеИмяФайла ), ТабДок . ИспользуемоеИмяФайла , "Табличный документ " + Строка ( Индекс + 1 ) ) + ".pdf" ;
ПереместитьФайл ( ФайлPDF . ПолноеИмя , НовоеПолноеИмя ) ;
// Добавим в массив вложений, который вернет в итоге наша функция
ФайлPDF = Новый Файл ( НовоеПолноеИмя );
МассивФайлов . Добавить ( ФайлPDF );
// Возвращаем старое имя принтера, чтобы не менялись параметры печати по-умолчанию
ТабДок . ИмяПринтера = СтароеИмяПринтера ;
КонецЦикла;
// Закрываем утилиту - иконка в трее пропала. Что примечательно, закрывать раньше времени очередь печати нельзя, а то пропадут все задания, но так как мы с нетерпением ждем появления каждого файла и в этот момент уже дождались, то тут все ок.
УтилитаПечати . cClose ();
УтилитаПечати = Неопределено;
НастройкиПоУмолчанию = Неопределено;
Ну а дальше уже дело техники, что с этими файлами делать. Я, например, использую встроенный в УТ почтовый клиент, создаю новое письмо, заполняю адрес из контактной информации контрагента, добавляю туда вложения и открываю письмо пользователю для просмотра и принятия решения об отправке, а pdf-ки с диска удаляю.
Естественно, мой код не претендует на истину в последней инстанции - может где и коряво получилось, но вобщем-то он работает и свою задачу выполняет. Более элегантного решения я во всяком случае не нашел. Принимаю конструктивную критику и предложения
upd 08.10.2010
Создал аналогичную функцию с использованием внешней компоненты Yoksel. Код проще и прозрачнее, файлы формируются намного быстрее, нет заморочек с искусственными задержками времени, но печатная форма добавляется в документ картинкой, причем не очень хорошего качества, плюс требуется создание временного файла на диске для последующей конвертации.
// Функция формирует файлы для отправки по электронной почте с помощью внешней компоненты Yoksel.dll
//
Функция Йоксель_СформироватьФайлыДляОтправки ( ТабличныеДокументы , Путь )
Попытка
ЗагрузитьВнешнююКомпоненту ( КаталогПрограммы () + "Yoksel.dll" );
Йоксель = ПолучитьCOMОбъект ( "" , "Йоксель" );
КонвертерPDF = Йоксель . СоздатьГрафическийКонвертерPDF ();
Исключение
Предупреждение ( "Не удалось загрузить внешнюю компоненту Yoksel! Сообщите администратору системы!" , 20 );
Возврат Неопределено;
КонецПопытки;
МассивФайлов = Новый Массив ;
Состояние ( "Создание файлов . " );
Для Индекс = 0 По ТабличныеДокументы . Количество () - 1 Цикл
// Получаем табличный документ
ТабДок = ТабличныеДокументы [ Индекс ];
// Формируем временный файл xls
ИмяФайлаБезРасширения = ?( ЗначениеЗаполнено ( ТабДок . ИспользуемоеИмяФайла ), ТабДок . ИспользуемоеИмяФайла , "Табличный документ " + Строка ( Индекс + 1 ) ) ;
ТабДок . Записать ( Путь + ИмяФайлаБезРасширения + ".xls" , ТипФайлаТабличногоДокумента . XLS97 );
// Удаляем временный файл xls
УдалитьФайлы ( Путь + ИмяФайлаБезРасширения + ".xls" );
// Добавляем в массив вложений
ФайлPDF = Новый Файл ( Путь + ИмяФайлаБезРасширения + ".pdf" );
МассивФайлов . Добавить ( ФайлPDF );
КонецЦикла;
Все платформы 1С, начиная с версии 8.2, а следовательно 8.3 и 8.4 могут сохранять табличные документы, печатные формы и отчеты в формате PDF, причем для этого не нужно устанавливать другие программы.
Как сохранить из 1С 8.2 в PDF
Для этого нужно подготовить документ к печати и перейти в меню «Файл — Сохранить как…» и в поле «Тип файла» выберите Документ PDF (*.pdf). Для примера сохраним в программе 1С Управление торговлей, редакция 10.3 печатную форму «Приходный кассовый ордер (ПКО)»:
Как сохранить документ из 1С 8.3 в файл PDF
В платформе 8.3 сохранение происходит аналогично, только здесь меню «Файл — Сохранить как…» находится под кнопочкой со стрелкой внизи в поле «Тип файла» выберите Документ PDF (*.pdf). Дальше, аналогично – в поле «Тип файла» выбрать «Документ PDF.
Если пункт меню «Сохранить как…» недоступен в 1С, то сначала нажмите левой кнопкой мыши в любом месте документа, который хотите сохранить и после этого пункт меню должен стать доступным:
Куда пропало меню «Сохранить» в 1С 8.3.15
После обновления платформы на версию 8.3.15 изменилось расположение пунктов «Сохранить как…», теперь для его вызова нужно нажать на кнопку с тремя вертикальными точками, в правом верхнем углу формы:
Как программно сохранить табличный документ в PDF?
Часто программистам нужно программно сохранить табличный документ 1С в формате PDF. Для этого нужно использовать метод Записать() и в качестве второго параметра указать ТипФайлаТабличногоДокумента.PDF
AppShell = Новый COMОбъект ( "Shell.Application" );
AppShell . ShellExecute ( PDF_File , "" , "" , "print" , 0 );
Процедура Печать_PDF_Файла_Фоновая ( МассивФайловPDF , ИмяУстройства = "" ) Экспорт
// Процедура печатает pdf-файлы (из списка) в фоновом режиме (без участия пользователя)
// Параметры процедуры:
// МассивФайловPDF - массив элементов типа "Файл" или массив структур с ключами "ПолноеИмя" и "Имя"
// ИмяУстройства - имя МФУ или принтера в системе
WbemScripting = Новый COMОбъект ( "WbemScripting.SWbemLocator" );
ConnectServer = WbemScripting . ConnectServer ( "" , "" , "" , "" ); //Задания от всех пользователей
ConnectServer . Security_ . impersonationlevel = 3 ; // Получение нужных прав
ConnectServer . Security_ . Privileges . AddAsString ( "SeLoadDriverPrivilege" );
Для Каждого ФайлPDF Из МассивФайловPDF Цикл
WScriptShell . Run ( Путь_AdobeReader + " /N /T " + ФайлPDF . ПолноеИмя + ?( ЗначениеЗаполнено ( ИмяУстройства ), " " + ИмяУстройства , "" ), 0 );
ДобавленоЗадание = Ложь;
ТекущееВремя = ТекущаяДата ();
// 40 секунд на добавление задания см.ОбработкаПрерыванияПользователя
Пока Не ДобавленоЗадание И ТекущаяДата () ТекущееВремя + 40 Цикл
ОбработкаПрерыванияПользователя ();
Для Каждого PrintJob Из ConnectServer . InstancesOf ( "Win32_PrintJob" ) Цикл
ОбработкаПрерыванияПользователя ();
ДобавленоЗадание = PrintJob . Document = ФайлPDF . Имя ;
КонецЦикла;
КонецЦикла;
// Ожидание завершения печати
Пока ConnectServer . InstancesOf ( "Win32_PrintJob" ). Count > 0 Цикл
КонецЦикла;
// Получение имени процесса
НомерСимвола = Найти ( Путь_AdobeReader , "\" );
Пока НомерСимвола > 0 Цикл
Путь_AdobeReader = Сред ( Путь_AdobeReader , НомерСимвола + 1 );
НомерСимвола = Найти ( Путь_AdobeReader , "\" );
КонецЦикла;
// Удаление процесса
WScriptShell . Run ( "taskkill /f /im " + Путь_AdobeReader , 0 );
Читайте также: