Блокировка документа от изменений

6 3

Вводная: Юристам требуется создавать договорные документы на основании заявки. Заявка это документы формата EXCEL и WORD. На её основании создают договорные документы, это документы в формате WORD. После создания документа, в процессе согласования есть вариант, что в заявку надо добавить пункты или изменить существующие(так что переформатировать в PDF не корректно для данного бизнес процесса), в следствии чего заявку редактируют. Далее заявка попадает к юристам, и они заново делают договор.

Условия

- Нельзя изменять бесконтрольно заявку на документ, только с согласия и уведомления Юристов

- Нельзя изменять бесконтрольно договорной документ созданный Юристами и находящийся на согласовании.

Решение 1. Блокировка версии документа и создание сразу новой версии документа

У данного решения есть два "но":

  • ненадежность. Что версию с " блокировкой " все таки можно снять;
  • появляется бардак в документах. Может появиться очень много не нужных версий документа.
DocID     = 390048
EDocument = EDocuments.GetObjectByID(DocID)
EDocLastVersionNum = GetLastEDocumentVersionNum(EDocument)
EDocVersions       = EDocument.Versions
EDocLastVersion    = EDocVersions.Values(EDocVersions.Count-1)
EDocLastVersion.lock // блокировка версии
EDocLastVersion.CreateClone(' Клонирование ';vsActive; false )

Решение 2. Установка ЭЦП

Из плюсов - версия документа раз подписана, становится невосприимчива к изменению. Из минусов - сертификаты надо обновлять.

Посмотрев оба решения и сделав их в коде, понял, что лучшее решение для меня это решение с ЭЦП. Самой большой трудностью стало то, что надо подписывать "тихо" и без участия пользователей. Подписывание происходит в блоке “Сценарий” в его вычислениях. То есть автор подписи становиться великий ISBuilderSystem. А тут неожиданный трабл возник –“Файл обмена личной информацией” с расширением *.pfx требуется разворачивать в профиле пользователя на компьютере. А такого места нет, даже на сервере, для данного пользователя.

Решение у меня не самое идеальное - это ключик в папке на сервере. Оттуда и забирает код через константу.

FreeException() // очистка исключений
ExceptionsOff() // защита от вылетов
DocID     = 390048 // ид документа
EDocument = EDocuments.GetObjectByID(DocID)
EDocLastVersionNum = GetLastEDocumentVersionNum(EDocument)
EDocVersions       = EDocument.Versions
Version            = EDocVersions.Values(EDocVersions.Count-1)     //получить версию документа которую надо подписать
// Найти подходящий сертификат
CertificateFound       = False
CertificateForSignInfo = nil
//Получить список сертификатов
CurUserName      = Application.Connection.UserName
JobPerformerUser = ServiceFactory.GetUserByName(CurUserName)
// JobPerformerUser = ServiceFactory.GetUserByID(104330) // конкретный исполнитель
CertificateList  = ServiceFactory.GetUserECertificateList(JobPerformerUser)
//Получить первый сертификат
CertificateList.Reset
// Пока не достигнут конец списка сертификатов или сертификат не найден
stop = 0
колво = CertificateList.Count
if колво <100   and    колво <<>>0
      while not CertificateList.EOF
            //Получить информацию о сертификате
            CertificateForSignInfo = CertificateList.Value
            имя  = CertificateForSignInfo.Name      
            CertificateList.Next
            stop = stop + 1
            if stop ==20 // защита от вечного цикла
                exit()
            endif
      endwhile
      //Получить сертификат из БД из компоненты "Пользователи" (открытый ключ)
      Certificate = CertificateForSignInfo.ECertificate  
      // Определить исполнителя задания
      JobPerformerUser = ServiceFactory.GetUserByName("Administrator")
      //Загрузить сертификат из личного хранилища
      pass = '1'
      Значение = Конст("pcSertIsBilder ") // путь сертификата
      Certificate.Load(Значение;pass)     // загрузить сертификат из файла
      Certificate.Thumbprint = Certificate.Thumbprint
      //Comment = time()&' Комментарий : Документ подписан автоматически в рамках задания с ИД: '& Object.ID
      //stAuthenticating – визирующая подпись;
      //stApproving      – утверждающая подпись.
      //Version.SignByAnotherUser(Certificate; JobPerformerUser; stAuthenticating; '' /*Comment*/) // подписания за кого
      Version.Sign(Certificate; stAuthenticating; '' /*Comment*/)  // автор сам подписывает
      ExceptionsOn()
      if ExceptionExists()                                                                                                                                                   
          E = GetLastException()
          Object.ActiveText = pProverka(E.Message)
      endif  
endif

P.S. Может кому-то поможет это (я потратил 3 дня на решения и отладку).

Валентина Писанова

Добрый день, Юрий.

Достаточно много информации по вашей потребности содержится в материале FLY-DIRECTUM: часть 5. И верить в то, что не было измен. В тексте статьи рассмотрены различные варианты решения задачи и даны ссылки на описания других решений. Плюс достаточно оживлённая переписка в комментариях.

Два нюанса по вашим решениям:

1. Вы пишете "пользователь сразу увидит, что версия "в блоке", и сможет снять её".

Блокировку с версии может снять только тот, кто её поставил. Или администратор. Если мы блокируем версию документа от имени служебного пользователя, вероятность её непреднамеренного снятия будет стремиться к нулю.

2. Не совсем понятно, чем решение установки ЭП лучше решения установки блока в части "бардака в документах"? Необходимость создания новой версии возникает в обоих случаях.

Валентина Писанова: обновлено 14.09.2017 в 14:42
Александр Чугунов

Юрий, по опыту блокировки от системного пользователя вполне достаточно. Можно снимать блокировку когда документ разрешили редактировать. Вот тут есть технические нюансы блокировки, если надо.

Артем Сунцов

Решение 1. "но" №3: при попытке переноса документа в архивное хранилище (по крайней мере в то, где запрещено редактирование) проверяется наличие блокировок самого документа и его версий. То есть, если служебные блокировки потом не снимать, может разрастись оперативное хранилище документов.

Решение 2. Чтобы не хранить закрытый ключ служебного пользователя в явном виде (хоть и на сервере) можете пересмотреть вопрос настройки самой системы: ввести служебного пользователя AD, настроив запуск служб под ним, и ему же устанавливать сертификаты (а также сможете выделить ему же служебный почтовый ящик, который сможете использовать для рассылки оповещений из системы и приёма обращений пользователей,...).

Авторизуйтесь, чтобы написать комментарий