Программный запрет создания новых версий документов.

16 8

Защита от "дурака" спасает только от неизобретательного дурака.
(С) Постулаты Трумена по программированию.

Любая система, зависящая от человеческой надежности, ненадежна.
(С) Законы ненадежности Джилба.

 

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

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

1. Запрет создания новой версии документа, вложенного в задачу (с разрешением в определенных заданиях).

Для запрета создания новой версии нам будет необходимы свойства 2го табличного раздела карточки документа (Информация о версиях хранится во 2ой табличной части карточки документа).

Добавляем в событие "Добавление После" Таблицы 2 карточки электронного документа:

  CanCreateVersion = TRUE  // изначально, при создании документа, новые версии создавать можно

  if not Object.Inserted  // необходимое условие для создания первой версии
    // Поиск задач "в работе"
    Search = Searches.Load('ATTACHED_TO_TASK_SEARCH')
    EDocInfo = EDocuments.ObjectInfo(Object.ID)
    Search.InitializeSearch(EDocInfo)
    Criteria = Search.SearchCriteria
    StateCriterion = Criteria.Add("TaskState")
    StateCriterion.Add("В работе") 
    StateCriterion.ValuesBuildType = btOnly 
    StandardRouteCriterion = Criteria.Add("StandardRoute")
    // код ТМ, по которому ищем вложенным наш документ    
    StandardRouteCriterion.Add(Конст("CMAgreementStandardRoute"))
    StandardRouteCriterion.ValuesBuildType = btOnly      
    TasksInWork = Searches.Execute(Search)
    // Анализ
    if TasksInWork.Count > 0
      CanCreateVersion = FALSE  // если есть задачи в работе - запретим создавать новые версии
      // пройдемся по всем найденным задачам
      foreach TaskInfo in TasksInWork
        Task = TaskInfo.Task   
        Jobss = Task.DetailDataSet(3)
        if Jobss.RecordCount > 0   
          Jobss.First()    
          While not Jobss.EOF
            // разрешим создание новых версий только на определенных этапах ТМ
            if ((SubString(Jobss.Subject; ' '; 1) == 'Доработка') 
             or (SubString(Jobss.Subject; ' '; 1) == 'Контроль')) 
              and (Jobss.JobState == "В работе")
                CanCreateVersion = TRUE
            endif
            Jobss.Next()
          endwhile       
        endif 
      endforeach
    endif
  endif  

  // Запретим создание новых версий документа  
  if not CanCreateVersion
    Raise(CreateException(''; 
         'Создавать новые версии можно только на этапах доработки документа по ТМ.'; ecWarning))
  endif

2. Запрет создания новой версии документа.

Запретим создавать новые версии документам по произвольным условиям без привязки к типовым маршрутам.

а) Набор реквизитов карточки электронного документа:

Добавить новый реквизит типа Признак со значениями "Да/Нет", допустим, "ДаНет5".

б) Событие "Добавление После" карточки электронного документа:

Object.ДаНет5 = 'Да'   // Разрешим создавать новые версии документа

в) Событие "Добавление После" Таблицы 2 карточки электронного документа:

if Object.ДаНет5 == 'Нет'
  Raise(CreateException(''; 'Создание новых версий запрещено.'; ecWarning))
endif

г) В необходимых вычислениях, например, при расчете какого-либо реквизита, присваеваем реквизиту "ДаНет5" значение "Нет", это не позволит пользователям создавать новые версии документов.

Алексей Немцев

Алексей, поясните пожалуйста, как создание версии документа приводит к "нарушению логики любого типового маршрута и построению листов согласования"?

Алексей Долгих

Больше к построению листа согласования.

Приведу пример: лист согласования строится по ЭЦП на документе по определенной его версии и примечаниям выполненных заданий из ТМ. Пользователь перед подписанием может запросто создать еще одну версию документу, к примеру, его не устроил текст, а так как документ наверняка уже подписан другими, он внесет корректировки через новую версию. Или инициатор проявил инициативу и мониторил после каждого согласующего их комментарии в задаче и сразу вносил корректировки новыми версиями. При этом общий список ЭЦП будет разделен по нескольким версиям документа и при построении листа согласования он будет только из тех подписей, что на указанной версии документа.

Нарушение логики ТМ может быть в организационном понимании, например, при согласованиях договора должна подписываться ЭЦП последняя версия документа, но согласующий по предыдущему примеру может создать еще одну версию документа и последующие согласующие уже будут ставить ЭЦП не на той версии.

Ольга Мельникова

У меня не реализуется выполнения данного кода по первому варианту, система ошибки не выдает.

Дмитрий Третьяков

В своей организации вторым методом пользуемся уже давно и это избавило нас от многих проблем, связанных с созданием новой версии в процессе согласования документа. НО! При импорте документа в новую версию любым из предоставляемых системой способов (из файла, из шаблона, из документа), исключение, прописанное в коде табличной части карточки, не срабатывает. На экране появляется замечательная ошибка "Access violation at address 058F99AD in module sbedms.bpl", новая версия не создается, но пользователь пугается и начинает звонить в службу поддержки организации с недоуменным вопросом "а чо это?" :) Кто уже сталкивался с подобной проблемой и нашел путь/пути ее решения, коллеги?

Дмитрий Тарасов

А в службу поддержки обращались? Мне кажется это платформенный глюк.

Руслан Бапин

Некоторое время назад тоже понадобилось запретить создание новых версий документа на определенной стадии ЖЦ. Тоже решил использовать событие Таблица2.ДобавлениеДо, и тоже столкнулся с ошибкой "Access violation..." при импорте. Попробовал использовать два события Запись.СохранениеДо (для проверки и выдачи исключения) и Запись.Открытие (для запоминания количества версий). Но столкнулся с другой бедой - если пользователь после получения сообщения о невозможности создания новой версии еще раз нажмет на ОК в том же самом диалоге создания версии (ведь он в этот момент все еще остается открыт), то возникает ошибка "В списке методов добавляемый метод уже существует".

Поразмыслив, решил использовать оба метода, но каждый - только для "своих" случаев. Таким образом, пришлось вставить код в три события (при открытии запоминается количество). Сработало. Посмотрите, что получилось (комментарии в коде поясняют то же самое, что я написал выше, специально оставил, чтобы потом не ломать голову, зачем такие ухищрения :)

Обработчик события Запись.Открытие

  // Запоминаем текущее количество версий, необходимо для реализации
  // запрета создания новой версии документа, находящегося в стадии ЖЦ, отличной от "Инициализация"
  Object.Params.SetVar("VersionsCount"; Object.Versions.Count)

Обработчик события Запись.СохранениеДо

  // Запрет создания новой версии документа, находящегося в стадии ЖЦ, отличной от "Инициализация".
  // Реализован сразу двумя способами:
  // 1. Для случаев, когда версия создается на основе одной из предыдущих версий этого же документа,
  //    запрет реализован в событии "Таблица2.ДобавлениеДо"
  // 2. Для остальных случаев запрет реализован в событии "Запись.СохранениеДо" (т.е.здесь)
  // 
  // Такой подход нужен для обхода следующих ограничений:
  // 1. Если реализовать только в событии "Запись.СохранениеДо", то если при попытке создания новой версии пользователь
  //    после получения сообщения еще раз нажмет на ОК, возникает ошибка "В списке методов добавляемый метод уже существует".
  // 2. Если при импорте из файла, шаблона или другого документа в событии "Таблица2.ДобавлениеДо" сгенерировать исключение,
  //    то возникает ошибка "Access violation at address ... in module 'sbedms.bpl'. Read of address 00000000"
  //    (известный дефект платформы) 
  //
  if Object.ISBEDocLifeStageName <<>> "Initialization"
    PrevVersionsCount = Object.Params.FindItem("VersionsCount")
    CurrentVersionCount = Object.DetailDataSet(2).RecordCount
    if not VarIsNull(PrevVersionsCount)
      if PrevVersionsCount <> CurrentVersionCount
        Raise(CreateException("excNewVersionsNotAllowed"; "Создание новой версии возможно только в стадии инициализации/доработки!"; ecWarning))
      endif
    endif
  endif

Обработчик события Таблица2.ДобавлениеДо

  // Запрет создания новой версии документа, находящегося в стадии ЖЦ, отличной от "Инициализация".
  // Реализован сразу двумя способами:
  // 1. Для случаев, когда версия создается на основе одной из предыдущих версий этого же документа,
  //    запрет реализован в событии "Таблица2.ДобавлениеДо" (т.е.здесь)
  // 2. Для остальных случаев запрет реализован в событии "Запись.СохранениеДо"
  // 
  // Такой подход нужен для обхода следующих ограничений:
  // 1. Если реализовать только в событии "Запись.СохранениеДо", то если при попытке создания новой версии пользователь
  //    после получения сообщения еще раз нажмет на ОК, возникает ошибка "В списке методов добавляемый метод уже существует".
  // 2. Если при импорте из файла, шаблона или другого документа в событии "Таблица2.ДобавлениеДо" сгенерировать исключение,
  //    то возникает ошибка "Access violation at address ... in module 'sbedms.bpl'. Read of address 00000000"
  //    (известный дефект платформы) 
  //
  if Object.ISBEDocLifeStageName <<>> "Initialization"
    if EDocumentVersionSource.SourceType == edvstEDocumentVersionCopy
      if EDocumentVersionSource.Value.Parent.ID = Object.ID
        Raise(CreateException("excNewVersionsNotAllowed"; "Создание новой версии возможно только в стадии инициализации/доработки!"; ecWarning))
      endif
    endif
  endif

 

Ильдус Нуретдинов

"В списке методов добавляемый метод уже существует" данная ошибка всё равно остается. :(

Руслан Бапин

> "В списке методов добавляемый метод уже существует" данная ошибка всё равно остается. :(

Ильдус, Вы делали по моей рекомендации (добавили приведенный код в обработчики трех событий)?

Дополнительные вопросы:

  1. У вас в схеме жизненного цикла есть стадия с наименованием "Initialization"?
  2. Какая версия DIRECTUM?
  3. Можно ли вывести значение EDocumentVersionSource.SourceType? Например, вставить вывод в код обработчика события Таблица2.ДобавлениеДо

  // Запрет создания новой версии документа, находящегося в стадии ЖЦ, отличной от "Инициализация".
  // Реализован сразу двумя способами:
  // 1. Для случаев, когда версия создается на основе одной из предыдущих версий этого же документа,
  //    запрет реализован в событии "Таблица2.ДобавлениеДо" (т.е.здесь)
  // 2. Для остальных случаев запрет реализован в событии "Запись.СохранениеДо"
  //
  // Такой подход нужен для обхода следующих ограничений:
  // 1. Если реализовать только в событии "Запись.СохранениеДо", то если при попытке создания новой версии пользователь
  //    после получения сообщения еще раз нажмет на ОК, возникает ошибка "В списке методов добавляемый метод уже существует".
  // 2. Если при импорте из файла, шаблона или другого документа в событии "Таблица2.ДобавлениеДо" сгенерировать исключение,
  //    то возникает ошибка "Access violation at address ... in module 'sbedms.bpl'. Read of address 00000000"
  //    (известный дефект платформы)
  //
  if Object.ISBEDocLifeStageName <<>> "Initialization"

   ShowMessage(EDocumentVersionSource.SourceType)
    if EDocumentVersionSource.SourceType == edvstEDocumentVersionCopy
      if EDocumentVersionSource.Value.Parent.ID = Object.ID
        Raise(CreateException("excNewVersionsNotAllowed"; "Создание новой версии возможно только в стадии инициализации/доработки!"; ecWarning))
      endif
    endif
  endif

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