Добрый день, меня зовут Владимир, я разработчик 1С.
В настоящее время работаю в Programming Store. Я специализируюсь на конфигурации «1С:ЗУП». В процессе работы приходится решать различные задачи в интересах заказчиков. С одной из них я хотел бы вас познакомить.
Содержание:
1. Как родилась идея доработки.
2. Код функции для чтения рdf-файла.
3. Резюме.
Задача от клиента выглядела в принципе несложно: внедрить личный кабинет сотрудника. Но, как всегда, дьявол покопался в деталях. У заказчика существовало достаточно большое количество внутренних заявлений, до реализации которых у компании 1С руки не дошли. Для таких случаев в личном кабинете сотрудника существует произвольное обращение. Но там есть маленький нюанс: параметры, которые мы создаем в произвольном шаблоне, не передаются в «1С:ЗУП». И тем не менее они нужны для дальнейшей обработки заявлений: автоматического отклонения обращений, создания документов и прочего.
На момент написания статьи компания 1С вроде бы разрешила доработку личного кабинета сотрудника, написанного на «1С:Элементе», но меня терзали сомнения, что обновление доработанного функционала будет происходить гладко. Очень не хотелось оставлять заказчику такую проблему. Очень, очень не хотелось. Если честно, меня охватило уныние: дорабатывать личный кабинет чревато проблемами, а параметры никак не хотели прилетать в обращениях сотрудников.
Единственное, что приходило из личного кабинета в «1С:ЗУП», — это приложенный файл формата pdf. Хороший формат, удобный. 1С даже умеет в него писать. Но не умеет читать. Кому в здравом уме придет в голову программно читать файл pdf? Я в своей практике такого не помню. Предыдущий опыт говорил, что это невозможно. Но для очистки совести решил погуглить. Результат меня очень удивил: оказывается, есть утилита РdfToText, которая преобразовывает pdf-файл в текстовый (если, конечно, файл pdf был собран из текста, а не из картинок). В заявлении, которое приходит из личного кабинета в виде pdf-файла, есть все параметры, необходимые нам. Таким образом, если мы сможем преобразовать файл в текст, а затем распарсить, у нас появляется возможность получить так необходимые нам параметры.
Примеры по работе с утилитой PdfToText можно найти на Инфостарте. Правда, при использовании данного примера меня поджидала неприятность: антивирус на сервере заказчика заблокировал выполнение утилиты «hstart.exe». Но оказалось, что она не обязательна — удалось написать скрипт без нее.
Код функции для чтения рdf-файла
Привожу код функции, которая читает pdf-файл и дальше отправляет его на анализ содержимого:
Процедура ПрочитатьПараметрыОбращения() Экспорт
КаталогВременныхФайлов = КаталогВременныхФайлов();
МакетУтилиты = ПолучитьОбщийМакет("кэдо_PDFToText");
Адрес = ПоместитьВоВременноеХранилище(МакетУтилиты, Новый УникальныйИдентификатор);
ФайлУтилиты1 = КаталогВременныхФайлов + "pdftotext.exe";
ДанныеХранилища = ПолучитьИзВременногоХранилища(Адрес);
УдалитьИзВременногоХранилища(Адрес);
ДанныеХранилища.Записать(ФайлУтилиты1);
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| ОбращениеКабинетСотрудникаПрисоединенныеФайлы.Ссылка КАК Ссылка
|ИЗ
| Справочник.ОбращениеКабинетСотрудникаПрисоединенныеФайлы КАК ОбращениеКабинетСотрудникаПрисоединенныеФайлы
|ГДЕ
| ОбращениеКабинетСотрудникаПрисоединенныеФайлы.ВладелецФайла = &ВладелецФайла";
Запрос.УстановитьПараметр("ВладелецФайла", ЭтотОбъект.Ссылка);
РезультатЗапроса = Запрос.Выполнить();
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
Попытка
ДанныеФайла = РаботаСФайлами.ДанныеФайла(ВыборкаДетальныеЗаписи.ССылка, РаботаСФайламиКлиентСервер.ПараметрыДанныхФайла());
Исключение
ИменаСобытийЖР = ИнтеграцияКабинетСотрудника.ИменаСобытийЖР();
ИнтеграцияУправлениеПерсоналомОбмен.ЗаписатьОшибкуПолученияДанныхФайла(ИменаСобытийЖР, ВыборкаДетальныеЗаписи.ССылка, ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
Возврат ;
КонецПопытки;
ДвоичныеДанныеФайла = ПолучитьИзВременногоХранилища(ДанныеФайла.СсылкаНаДвоичныеДанныеФайла);
ИмяФайла = ИнтеграцияУправлениеПерсоналом.ИмяФайлаБезРасширения(ДанныеФайла.ИмяФайла, ДанныеФайла.Расширение);
КонецЦикла;
Если ДанныеФайла <> Неопределено тогда
ПолноеИмяФайла = КаталогВременныхФайлов + ДанныеФайла.ИмяФайла;
полноеИмяТекстовогоФайла = ИмяФайла + ".txt";
ПолноеИмяФайла = КаталогВременныхФайлов + "temp.pdf";
ДвоичныеДанныеФайла.Записать(ПолноеИмяФайла);
ТекстКоманды = "" + КаталогВременныхФайлов + "pdftotext.exe -enc UTF-8 """ + ПолноеИмяФайла + """ """ + КаталогВременныхФайлов + "temp.txt""";
WshShell = Новый COMОбъект("WScript.Shell");
WshShell.Run(ТекстКоманды, 5, 1);
Текст = Новый ЧтениеТекста(КаталогВременныхФайлов+"temp.txt",КодировкаТекста.UTF8);
Стр = Текст.ПрочитатьСтроку();
ПолнаяСтрока = Стр;
Пока Стр <> Неопределено Цикл
Стр = Текст.ПрочитатьСтроку();
ПолнаяСтрока = ПолнаяСтрока + Стр;
КонецЦикла;
Текст.Закрыть();
УдалитьФайлы(КаталогВременныхФайлов + "temp.txt");
УдалитьФайлы(КаталогВременныхФайлов + "pdftotext.exe");
УдалитьФайлы(ПолноеИмяФайла);
ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыXML(ПолнаяСтрока," ");
ПроанализироватьСтрокуИЗаполнитьРеквизиты(ПолнаяСтрока);
КонецЕсли;
КонецПроцедуры
Анализ параметров, которые нам требуется извлечь, позволил их разделить на две части: различные даты и все остальное. Для всего остального я планировал использовать метод шаблона: задаю пару слов, программно ищу их, что оказалось между ними — считаю параметром. Для дат использовалась следующая идея: месяцев у нас 12, даты идут в виде «1 мая 2025 года». Таким образом я по очереди ищу название месяца, если нахожу, то символы перед — это число даты, символы после — год даты. Поскольку дат может быть несколько, то мы их просто нумеруем: к примеру, первая дата — это дата заявления, вторая дата – дата начала отпуска, третья дата – дата окончания.
Эти настройки мы прикрепляем к шаблону, вот так (ну естественно, шаблон доработан):
Подведу итоги. Клиент получил то, что хотел: внедренный кабинет сотрудника с реализованными требованиями. Причем требования внедрены с минимальным вмешательством в существующее решение. «1С:ЗУП» доработан с помощью расширения, личный кабинет сотрудника оставлен вообще без изменений. То есть грядущие преобразования конфигурации и личного кабинета нам не так страшны, как если бы мы поменяли их. Реализованная доработка достаточно несложно расширяется, что позволит заказчику в случае необходимости с небольшими затратами расширить функционал.
Пользуясь случаем, хочу выразить благодарность заказчику за интересную задачу.