понедельник, 29 октября 2012 г.

Клиент Notal System - перехват событий в офисных программах

Постановка проблемы
Большинство документов СЭД (системы электронного документооборота) редактируются в офисных программах - нас интересуют ставшие стандартом де-факто Ms Office и Open Office. В них требуется научиться делать следующие вещи:
  • Перехватывать закрытие документа
  • Перехватывать печать документа
  • Отличать документ, полученный из Notal System, от просто документа на локальном компе
  • Различать взятые из Notal System документы по типу - взятые на просмотр и взятые на редактирование
  • Различать, из какой именно базы Notal System взят документ - пользователь может с одного компа работать с несколькими базами
Если мы можем перехватить печать документа и можем понять, что он получен из Notal System, то дальше можем после печати сохранить новую версию в СЭД или более интересные штуки типа логирования печати и т.п.

Требования к опознанию документов как взятых из СЭД Notal System
Считаем, что вмешиваться во внутреннюю структуру документа мы не можем - для офисных документов это в принципе возможно, но хотелось бы иметь механизм, который бы не зависел от типа файла и мог бы быть распространен на другие типы файлов (к примеру, на инженерную графику - t-flex и т.п. имеют встроенные языки программирования, так что в будущем и на них можно портировать те же механизмы.
То есть у нас имеется не так много способов различать файлы:
  • Складывать взятые из СЭД файлы в определенную папку (или структуру папок)
  • Записывать имя файла в БД на локальном компе и потом сверяться с этими записями
  • Всю нужную информацию кодировать в имени файла
Поскольку СЭД Notal System работает в веб-интерфейсе, то не всё подконтрольно: разные браузеры складывают документы в разные папки, причем не всегда это можно настраивать. Кроме того, использовать локальную БД нежелательно, поскольку это переусложнит клиентскую часть и может потеряться гибкость веб-технологий.
Опознавать документ будем по имени файла, причем это опознание должно быть устойчиво к некоторым модификациям имени файла которые делают браузеры: к примеру, при повторном скачивании файла браузеры по-разному модифицируют его имя - Opera добавляет в конце " (1)", " (2)" и т.д., Mozilla Firefox добавляет "-1", "-2" и т.д.

Структура имени файла документа из Notal System
Различать разные базы Notal System будем по ключевому числу NN - целое трехзначное число, желательно простое или произведение двух двузначных простых чисел. Зададим его и тогда формат взятого из Notal System документа будет таким (жирным выделены константные части:
iiii_vvvE=AAAAAAABBB=
где iiii - id документа в Notal System (переменое число знаков, цифры, не может начинаться с 0),
vvv - номер версии документа (переменое число знаков, цифры, не может начинаться с 0),
E - указатель на то, что документ взят на редактирование; для взятых на просмотр ставим знак V,
AAAAAAA - случайное число 7 цифр с ведущими нулями, если требуется. Должно быть больше 1000.
BBB - проверочный код, 3 цифры с ведущими нулями, если требуется; вычисляется по формуле BBB = AAAAAAA mod NN, т.е. остаток от деления AAAAAAA на ключевое число NN.
Знаки "_" и "=" задают структуру имени файла. Всё, что идет после второго знака "=", при аналие отбрасывается.
Структура имени файла позволяет узнать id документа и узнать, взят ли документ на редактирование или только на просмотр. Номер версии документа для работы программы не важен, но полезен для пользователя. Случайное число в имени файла гарантирует, что дважды взяв документ из СЭД мы получим разные имена файлов. Проверка соотношения чисел AAAAAAA и BBB позволяет с большой долей надежности установить базу Notal System, из которой взят документ.

Расчет вероятности ложного опознания базы-источника документа
Считаем, что сама специфическая структура имени файла однозначно указывает на то, что файл взят из СЭД Notal System. Пусть на локальном компьютере пользователя зарегистрированы две базы с ключевыми числами NN1 и NN2. Тогда вероятность того, что одновременно выполняются два соотношения
  • BBB = AAAAAAA mod NN1
  • BBB = AAAAAAA mod NN2
равна 1/НОК(NN1, NN2), где НОК - наименьшее общее кратное. Поскольку мы выбираем NN1 и NN2 простыми, то формула упрощается до 1/(NN1*NN2). Поскольку оба числа трехзначные, то полученная вероятность гарантированно меньше 10-4 и почти всегда меньше 10-5, что позволяет нам не заботиться о ложных срабатываниях (по крайней мере в первой версии клиентской части Notal System).

Необходимые доработки серверной части Notal System
  • Добавить в раздел общей информации системы ключевое число
  • Создать механизм задания ключевого числа - вручную или случайно из списка подходящих простых чисел (контроль того, что все эти числа для установленных на нашем сервере баз различны, осуществляем пока вручную)
  • Написать функцию API, которая запрашивает у базы ее ключевое число (понадобится для конфигурирования ini-файла клиента)


Информация в ini-файле на машине клиента
В файле notalconfig.ini, расположенном в папке C:\NotalSystem\conf\, раздел каждой базы (имя раздела [base*], где "*" означает любой текст без пробелов) должен содержать следующие строки:
URL = http://test.notalsystem.ru/ - веб-адрес базы Notal System
KeyNumber = 449 - ключевое число
Name = "Тест" - название базы: произвольный краткий текст, нужен для показа в диалоговых окнах и т.п.
Сейчас считаем, что пользователь руками редактирует ini-файл, позже можно сделать конфигуратор клиента.

Что должна делать клиентская программа в офисном пакете
Для каждого офисного пакета (и в будущем - для программ инженерной графики) настраиваем отдельно, но одинаковый функционал:
  • Перехватываем закрытие документа и определяем базу
    • Если он взят на редактирование и изменен, то предлагаем отправить новую версию документа в СЭД
  • Перехватываем печать документа и определяем базу
    • Если он взят на редактирование и изменен, то печатаем и после этого отправляем новую версию документа в СЭД. Вариант: спрашиваем пользователя, делать ли это, если нет, то не отправляем новую версию, но и не печатаем.
    • Если он взят на просмотр и изменен, то не печатаем. Вариант: предупреждаем об этом пользователя, проверяем, что он имеет право редактировать этот документ, предлагаем ему сохранить отредактированную версию в СЭД (тут используется механизм, который мы используем для добавления новых версий документов из 1С, т.е. не беря предварительно документ на редактрирование.
    • Если документ не был изменен, то печатаем без каких-либо иных действий.
Позже к этому функционалу можем добавить логирование печати (потребуются соответствующие функции API).

Особенности реализации перехвата событий в Ms Office
Нас интересуют только Ms Word и Ms Excel. В этих программах перехват событий организован по-разному.
В Excel подключенная надстройка загружается как рабочая книга, так что в контейнере ThisWorkbook размещаем предопределенную функцию Workbook_Open(), а в ней включаем перехват событий через специальный класс.
В Word в шаблоне, расположенном в папке Word\STARTUP, создаем модуль AutoExec с процедурой MAIN(), которая запускается при загрузке Word. Перехват событий в ней организуется аналогично Excel.

Особенности реализации перехвата событий в Open Office
В Open Office для всех типов файлов работает единый механизм, организация перехвата событий там требует отдельного описания.

среда, 17 октября 2012 г.

Распечатка документов из СЭД: проблема несовпадения

У нас на заводе автоматизированы несколько бизнес-процессов на Notal System - системе управления задачами и документооборотом. Вот в одном бизнес-процессе - ремонте модельной оснастки - обнаружилась засадливая проблема. Последовательность действий такова (упрощенно):
  • все начинается с создания дефектной ведомости - документа с описанием проблемы и необходимых действий (текстовый документ в формате Open Office)
  • создается задача и к ней цепляется дефектная ведомость
  • дефектная ведомость распечатывается и подписывается всяким начальством
  • задача передается на исполнение
  • ...(потом много чего происходит)...
  • после выполнения работ задача поступает в ОТК, который открывает дефектную ведомость и по ней проверяет, все ли работы выполнены.
И вот тут обнаруживается проблема - иногда оказывается, что дефектная ведомость пуста. То есть на бумаге-то она заполнена, а в электронном виде - нет. Все прелести электронного документооборота - псу под хвост.
В чем причина этой проблемы? Чисто технически, дефектная ведомость создается по шаблону в Notal System, то есть заполняется минимальный набор реквизитов, а собственно содержательная часть - дефекты и необходимые работы - являются неформализованной информацией и пишутся технологом в текстовом редакторе. То есть созданный в СЭД (системе электронного документооборота) по шаблону документ (файл) открывается на редактирование, редактируется, распечатывается и в СЭД отправляется новая версия. Вот в этой последней последовательности действий возможны ошибки:
  • документ взят на редактирование, отредактирован, распечатан, но новая версия в СЭД не отправлена (в СЭД такой документ будет виден как взятый на редактирование)
  • документ взят из СЭД на просмотр, отредактирована локальная копия, распечатана. В СЭД тогда будет только первоначальная, пустая по сути, редакция документа.
Что с этим делать? Вариантов несколько.
Радикальный вариант. Полностью отменить бумажные документы и перейти на электронные. Не годится по следующим причинам:
  • в цеху все равно нужна бумажная распечатка - проще к станку принести бумажку в кармане, чем компьютер;
  • всякое начальство привыкло к бумажкам и засадить их за компы - задача весьма сложная, требуется серьезная мотивация (проблемы ОТК таковой не являются);
  • подпись на бумажке все-таки более юридически значима, чем запись в базе данных и ЭЦП.
В общем, отметаем это решение за излишнюю радикальность.
Автоматизированное порождение конечного документа. Это как распечатка накладной из 1С: там все заполняешь в диалоговом окне, а потом нажимаешь на кнопку [Печать] и формируется печатная форма. Решение тоже не годится - слишком уж вариативно содержание дефекой ведомости, там могут быть и таблицы, и эскизы. То есть если бы дефектная ведомость была бы хорошо формализуемым документом, то она и порождалась бы из системы планирования производства, а не из СЭД. В конце концов, всегда есть такие категории неструктурированных документов - те же письма, к примеру. Надо решать задачу на уровне СЭД при условии, что документ будет редактироваться пользователем в текстовом редакторе или электронных таблицах - грубо говоря, в Ms Office или Open Office.
Административные и воспитательные меры. Что если воспитать/убедить/запугать пользователей, чтобы они отрабатывали правильную последовательность действий до конца? Это сделать надо, конечно, но человек вообще склонен делать ошибки - одна эта мера явно недостаточна.
Модификация функции печати. Что если при печати перехватывать это событие и автоматически обновлять версию документа в СЭД? Вот это - решение! Надо сделать следующее:
  • в редакторе опознавать документ как взятый из СЭД (мы же не хотим, чтобы пользователь не мог нормально работать с файлами на своем локальном компе);
  • при открытии в СЭД документа в режиме просмотра запретить его редактирование в текстовом редакторе - то есть документ распечатать можно, а изменить и потом распечатать - нельзя;
  • при печати документа если он взят на редактирование в СЭД сохранять в ней новую версию документа. То есть распечатал - документ закрылся и отправился в СЭД.
Осталось научиться перехватывать события печати и открытия документа в Open Office (в Ms Office умею), и запрограммировать клиентскую часть Notal System.