Сталкивались на предприятии с ситуацией, когда бухгалтерия на распечатанный, подписанный ЭП документ требует поставить живую подпись? «Как же так?!» - возмущаются пользователи - «Есть же электронная подпись». А в бухгалтерии все равно нужно подтверждение, что документ подписан. И желательно, чтобы «вот прямо» на распечатанном документе. Как в банке проставляют штамп «Исполнено» на платежках:
Давайте обсудим, как это можно сделать в DIRECTUM.
В системе DIRECTUM есть функции, позволяющие проставлять штамп, содержащий определенный текст, в документ. Необходимо учесть, что в документе могут быть как подписанные версии, так и не подписанные. Причем подписанных версий может быть несколько. Важным условием также является требование неизменности документа после простановки на него штампа.
Исходя из всего перечисленного можно выработать следующий алгоритм:
Примерно, вот так:
Данный функционал можно навесить на специальную кнопку на ТКЭД, можно создать отдельный расчет с возможностью выбора документа. Это уже на усмотрение пользователей и программистов системы.
Предложенный алгоритм был реализован в виде прикладной функции DIRECTUM на версии 5.2. Напомню, что функции по установке штампов на pdf-документах появились в версии 5.0.
Итак, код функции:
//Делаем проверку парметра функции EDocument. EDocument – переданный в функцию документ, преобразование которого необходимо выполнить // Не указан параметр "%s". Assert(Assigned(EDocument); LoadStringFmt('DIRE434A6BC_59D8_4AF4_A58D_5105D7C60DF6'; 'COMMON'; 'EDocument')) //Блокируем документ от изменения EDocument.Lock EMPTY_STR = '' NOT_FOUND = -1 PDF = 'PDF' // Тип документа по расширению Extension = EDocument.Info.Editor.Extension // Если уже PDF, подтвердить постановку штампов if Extension == PDF YES = 'Да' NO = 'Нет' Answer = MessageBox(ATTENTION_CAPTION; 'У данного документа уже есть версия в формате PDF^Создать новую версию документа со штампами на основе последней действующей подписанной версии?'; YES & "|" & NO; NO; NO) if Answer == NO EDocument.UnLock Exit() endif endif // Найти номер последней действующей подписанной версии LastVersionNumber = NOT_FOUND Versions = EDocument.Versions Index = 0 while Index < Versions.Count Version = Versions.Values(Index) if Version.CurrentState = vsActive and Version.Signed LastVersionNumber = Version.Number Extension = Version.Editor.Extension endif Index = Index + 1 endwhile if LastVersionNumber = NOT_FOUND EDocument.UnLock Raise(CreateException("ENoActiveVersionFound"; "У документа нет ни одной действующей подписанной версии"; ecWarning)) endif // Экспортировать последнюю подписанную версию ExportFile = Format("%s%s.%s"; ArrayOf(GetTempFolder(); EDocument.ID; Extension)) DeleteFile(ExportFile) EDocument.Export(LastVersionNumber; ExportFile; false; false; false) try // Преобразовать в PDF, если экспортировали версию, которая не являлась pdf-документом. if Extension <<>> 'PDF' WSDLFileName = GetConstant('DCTSConvertToPDFWSDL') PDFFile = Format("%s%s.pdf"; ArrayOf(GetTempFolder(); EDocument.ID)) DeleteFile(PDFFile) DCTSConvertFileToPDF(WSDLFileName; ExportFile; PDFFile) else PDFFile = ExportFile endif // Общие параметры штампов StampFilename = GetTempFolder() & "stamp.png" STAMP_COLOR = '000000' // Черный STAMP_FONT_FACE = 6 // Times New Roman STAMP_FONT_SIZE = 20 // ШТАМП С ДАННЫМИ ЭЦП ДОКУМЕНТА SignatureField = EMPTY_STR // Часть штампа с информацией об ЭЦП SignatureDate = EMPTY_STR SerialNumber = EMPTY_STR CertificateValidFrom = EMPTY_STR CertificateValidTo = EMPTY_STR SubjectName = EMPTY_STR SignatureAuthor = EMPTY_STR // Собрать информацию о параметрах ЭП SignatureFieldStringList = CreateStringList() Signatures = EDocument.Versions.Values(LastVersionNumber-1).Signatures if Signatures.Count > 0 SignatureIndex = Signatures.Count - 1 while SignatureIndex >= 0 Signature = Signatures.Values(SignatureIndex) //Найти утверждающую подпись if Signature.SignatureType <> stNone AuthorUser = Signature.Author Certificate = Signature.Certificate SerialNumber = Certificate.SerialNumber if Assigned(AuthorUser) and SerialNumber <<>> EMPTY_STR SignatureAuthor = AuthorUser.FullName SignatureType = IfThen(Signature.SignatureType = stApproving; 'утверждающая ЭП'; 'визирующая ЭП') CertificateValidFrom = FormatDate('D.M.YY'; Certificate.ValidFromDate) CertificateValidTo = FormatDate('D.M.YY'; Certificate.ValidToDate) SignatureDate = FormatDate('D.M.YY'; Signature.Date) ValidText = IfThen(Signature.IsValid; 'ЭП достоверна'; 'ЭП не достоверна') SignatureField = Format("Подписан ЭП: %s Серт.: %s, действ. %s - %s, тип: %s, достоверность: %s"; ArrayOf(SignatureAuthor; SerialNumber; CertificateValidFrom; CertificateValidTo; SignatureType; ValidText)) SignatureFieldStringList.Add(SignatureField) endif endif SignatureIndex = SignatureIndex - 1 endwhile // Сегодня ДД.ММ.ГГГГ CurrentDate = FormatDate('D.M.YY'; Today()) SignatureFieldStringList.Delimiter = CR StampText = CurrentDate & ', ' & SignatureFieldStringList.DelimitedText // Рамка штампа STAMP_BORDER = 1 STAMP_BORDER_THICKNESS = 8 // Сгенерировать изображение с текстом, содержащим информацию о параметрах ЭП GenerateTextImage(StampText; STAMP_BORDER; STAMP_BORDER_THICKNESS; STAMP_COLOR; STAMP_FONT_SIZE; STAMP_FONT_FACE; StampFilename; 0) // Добавить штамп в PDF-документ STAMP_SCALE = 30 PagesMode = 2 AddImageToPDFFile(PDFFile; StampFilename;;; PagesMode; nil; STAMP_SCALE) EDocument.UnLock // Импортировать документ в новую версию электронного документа EDocument.ImportFromFile(-1; 'Версия со штампами ЭЦП в PDF на основе последней подписанной'; PDFFile) OpenFile(PDFFile) endif except EDocument.UnLock endexcept
В результате работы данного функционала в электронном документе появится версия, содержимое которой неизменно и которая содержит штамп с информацией о ЭП, поставленных на документе.
Забавно, конечно, что если "прикопаться", то это уже совершенно не тот документ, который был подписан этой самой подписью
Так и бумажный документ, на котором дополнительно поставили "живую" подпись - уже "совсем не тот документ".
В меньшей степени
В штампе не хватает ИД документа и номера подписанной версии
Да ). Но теперь по распечатанному документу можно узнать, кто подписывался под документом с данным текстом.
Эту информацию не сложно добавить в текст, из которого будет формироваться изображение штампа. Что-то добавить, что-то убрать - это уже на усмотрение пользователей, программистов системы.
Интересно, насколько (и почему) такое решение устраивает бухгалтерию? Если они не доверяют электронной подписи, которую собственноручно поставил подписывающий (иначе зачем требуют живую подпись на распечатанном документе?), то за вывод штампа в документ отвечает вообще другой человек.
Я готов согласиться с тем, что штамп в документе может упростить визуальное восприятие электронной подписи при условии, что я доверяю самой подписи. Но я сомневаюсь, что наличие такого штампа само по себе хоть что-то подтверждает.
Хочу отметить, что были обращения от клиентов с просьбой реализовать такой функционал. Бухгалтерии нужно подшивать документы, и чтобы именно на этой распечатанной бумажке было видно, что документ подписан. Вариант с распечаткой информации о подписях на отдельном документе из не устраивает.
Я у одного заказчика делал аналогичную штуковину, Вера. Да чего уж там — почти в точности такую же :) Там на штамп возлагалась простая функция: показать кто, когда и каким сертификатом подписал документ. То есть штамп не заменял собою ЭП и не освобождал от обязанности контролировать наличие подписи на электронном документе и валидность сертификата. Из твоего последнего комментария вижу, что в данном случае задача была какой-то такой же.
В дополнение к первому комментарию Валентины скажу: документ со штампом не просто "не тот", а теоретически настолько не тот, что его вообще не стоило бы заносить в систему — только на печать. Потому что при наличии умысла у программиста есть возможность внести изменения в текст документа перед преобразованием в PDF и постановкой штампа. Возможно, я излишне параноик.
Да, так и есть. Нужно знать, к кому идти, если будут вопросы к документу.
Простановка штампа ЭП на документе, мне кажется - функционал, который должен быть в стандартной системе по умолчанию.
На текущем проекте реализовывали подобный механизм, правда с особенностями по сравнению с предложенным алгоритмом:
Далее отличается в части экспорта, его пока не делали и оставили на откуп пользователя. Если захочет сохранить как новую верию документ со штампом, то сохранит и импортирует, потому что и ошибочно может сформировать или просто нажмет кнопку, чтоб посмотреть, как будет выглядеть. Поэтому дальнейший алгоритм у нас следующий:
5. Преобразовываем выбранную версию документа в pdf.
6. Проставляем выбранные штампы.
Кстати, основными потребителями этого решения были также бухгалтеры, распечатывающие служебные записки, которые согласовываются в электронном виде и те, кто часто отправляет исходящие письма в сторонние организации.
В планах развития функционала из пожеланий:
Здравствуйте. Качество текста в штампе почему-то очень низкое. Я имею в виду четкость, резкость. Штамп как будто низкого разрешения, текст не четкий. Пробовал разные параметры менять, но красивого результата не добился. Так и должно быть? Прикладываю кусочек документа. Видно, что качество шрифтов в тексте и штампе разное
Алексей, чтобы штамп был красивый надо его генерить размером раза в 2 больше, потом при вставке сжимать, там коэффициент задавать можно.
Поставил на отдельную кнопку, но выдает ошибку, "Значение переменной EDocument" не определено, ошибка в строке 3
Как указать значение переменной этой? что я делаю не так?
Разбираемся в вопросе https://club.directum.ru/question/71614
Добавил кнопку карточку, все работает.
Можно ли эту кнопку вывести в контекстное меню документа, что бы каждый раз не открывать карточку, каждого документа?
Если можно то как?
Есть один нюанс, связанный с работой данного функционала: если компьютер пользователя включен в состав домена, то данный функционал не отрабатывает. На компьютере пользователя, не включенном в состав домена Windows данный функционал работает на 100% корректно.
Пока в процессе решения вопрос...
Дополнение: для корректной работы данного функционала необходимо наличие соответствующего ПО.
При обращении Certificate.SubjectName из сертификата вытаскивается то, что у него прописано в поле subject CN. Это прекрасно работает с нашими локальными сертификатами, т.к. у нас там прописывается ФИО владельца. Но с сертификатами выданными на организацию сторонними центрами в CN значится название организации, а фамилия владельца идет в G и имя (или имя и отчество) в SN. Т.е. в поле subject не просто CN = Вася Пупкин, а CN = ООО "Рога и Копыта" G = Вася SN = Пупкин.
Есть ли возможность обращаться к произвольным параметрам поля subject?
Вячеслав Савин, рекомендую задать отдельный вопрос в разделе Вопросов и сослаться на эту статью, если вы делаете по рекомендациям из нее. Так он попадет в рассылку и больше участников его увидит и подключится к ответу. Не забудьте поставить теги - Разработка и Электронная подпись, тогда быстрее подключатся те, кто на них подписаны.
Авторизуйтесь, чтобы написать комментарий