Структура XML-схемы маршрута задачи

30 3

На проекте может возникнуть следующий кейс: без использования механизма замещения передать новому сотруднику все ЗЗУ предыдущего. В этом случае, кроме SQL пригодится структура XML-описания типового маршрута, чтобы разобраться: где, что и как изменить...

Предупреждение. Исправление XML – это крайний случай не гарантирующий успех, особенно если нужно исправить зависший ТМ. Поскольку это не документированная возможность системы, то возможны непредвиденные ошибки типа «Invalid floating point operation», «Access violation», «Invalid class typecast» и прочие.

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

Известно, что каждая задача имеет свою копию маршрута, которая хранится в реквизите WorkflowDescription. Получить и отредактировать XML любой задачи можно с помощью следующего сценария:

  TaskID = InputDialog("ID задачи"; ""; "Number")
  Task = Tasks.GetObjectByID(TaskID)
  EditedXML = EditText(Task.WorkflowDescription)
  Button = MessageBox('Подтвердить изменения'; 'Сохранить изменения в XML?'; 'Да|Нет'; 'Нет'; 'Нет')
  if Button == 'Да'
    Task.Requisites("WorkflowDescription").Value = EditedXML
    Task.Save
  endif

Облегчить работу с полученной XML поможет любой текстовый редактор с подсветкой синтаксиса, например популярный Notepad++ со следующим набором плагинов:

  • XML Tools для быстрого форматирования XML в удобочитаемый вид;
  • Compare для поиска отличий двух текстов;
  • MIME Tools для кодирования и декодирования текста в Base64.

XML описание состоит из корневого узла Settings и 10 дочерних узлов:

<Settings>
	<Event>			<!--События типового маршрута-->
	<StartedAskableParams>	<!--Установки запрашиваемых параметров при выполнении ТМ-->
	<Params>		<!--Описание параметров (задаются по кнопке «Параметры»)-->
	<Properties>	<!--Описание свойств задачи (тема, текст, вложения...)-->
	<Blocks>		<!--Описание блоков типового маршрута и их свойств-->
	<Route>			<!--Описание связей между блоками-->
	<ExecutedBlocks><!--Список всех исполняемых блоков-->
	<CurrentBlocks>	<!--Описание текущих выполняемых блоков-->
	<RouteActions>	<!--Список действий типового маршрута-->
	<RouteRibbon>	<!--Описание ленты типового маршрута-->
</Settings>

 

Описание XML

Event – события типового маршрута

<Event>
	<InitScript>		<!--начало выбора -->
	<Script>			<!--завершение выбора -->
	<TaskStart>			<!--возможность старта -->
	<TaskAbortPossibility>	<!--возможность прекращения -->
	<TaskAbort>			<!--прекращение -->
	<OnTaskFormShow>	<!--показ формы-карточки -->
	<OnTaskFormHide>	<!--скрытие формы-карточки -->
</Event>

Каждый из этих обработчиков может быть пустой или содержать вычисления на языке ISBL, но в любом случае они имеют секцию CDATA.

<InitScript>
	<![CDATA[]]>
</InitScript>
<Script>
	<![CDATA[{5314B05F-CF9F-4F66-99EC-24992A5FB114}ICAvLyDT8fLg7e7i6PL8IPLl6vHyIOfg5OD36A0KICBUYXNrVGV4dCA9IExvYWRTdHJpbmcoJ0RJUjM4NUQzMUUyXzYxRUJfNDBDNl84MDQ4Xzk0M0E3NEQzNUIzQSc7ICdCUE0nKSAmIENSIC8vIM/w6Pfo7eAg8+Tg6+Xt6P86DQogIE9iamVjdC5BY3RpdmVUZXh0ID0gVGFza1RleHQ=]]>
</Script>

Текст обработчика, как и все текстовые данные XML, закодированы в MIME/Base64, что позволяет хранить символы не совместимые с синтаксисом XML. В начале текста проставляется специальный GUID – маркер того, что содержимое CDATA закодировано. Данный GUID всегда равен {5314B05F-CF9F-4F66-99EC-24992A5FB114}. Если его нет, код вычисления будет записан "как есть":

<![CDATA[ //  ТМДобавитьВложение("Эл.документ"; 204561)
 //  ТМДобавитьВложение("Эл.документ"; 204562)
... ]]>

 

StartedAskableParams – запрашиваемые параметры

Перечисляются все параметры, отмеченные как запрашиваемые в свойствах задачи:

  • Name – имя параметра, соответствует имени парамтера из узла Params;
  • Required – признак обязательности заполнения (возможные значения true и false);
  • Hint – описание запрашиваемого параметра.

Пример узла StartedAskableParams:

<StartedAskableParams>
	<AskableParam Name="Документ" Required="true" Hint=""/>
	<AskableParam Name="Comment" Required="false" Hint="Сопроводительная информация"/>
</StartedAskableParams>

 

Params – параметры задачи

Дочерние узлы Param содержат следующие атрибуты:

  • Name – имя параметра;
  • Type – тип параметра;
  • Description – заголовок параметра;
  • DescriptionLocalizeID – константа локализации описания свойства.

Type принимает значение 0 – 33 и соответствует TWorkflowDataType (типы данных делового процесса).

Пример узла Params:

<Params>
	<Param Name="Документ" Type="9" Description="Документ" DescriptionLocalizeID="COMMON.PICK_62"/>
</Params>

Для параметров типа «Признак» и «Коллекция признаков» свойства перечисляются у дочернем узле PickValues.

<Param Name="CreateAssignment" Type="3" Description="Создать поручение" DescriptionLocalizeID="">
	<PickValues>
		<PickValue Code="Y" Name="Да" NameLocalizeID=""/>
		<PickValue Code="N" Name="Нет" NameLocalizeID=""/>
	</PickValues>
	<Value Value="Да"/>
</Param> 

Значение в узле Value зависит от типа данных параметра. Значение параметра «Строка» хранится в CDATA, а остальные значения в виде строки.

<Param Name="Срок" Type="0" Description="Срок (ч.)" DescriptionLocalizeID="">
	<Value Value="6"/>
</Param>
<Param Name="Stage" Type="2" Description="Стадия" DescriptionLocalizeID="">
	<Value>
		<Value>
			<![CDATA[{5314B05F-CF9F-4F66-99EC-24992A5FB114}zubo5ODl8iDu8u/w4OLq6A==]]>
		</Value>
	</Value>
</Param>

 

Properties – свойств задачи

Содержит несколько дочерних узлов Property c атрибутами:

  • Name – наименование свойства;
  • Type – тип свойства, соответствует значениям типа TWorkflowDataType;
  • AllowedTypes – допустимые типы (строка значений типа TWorkflowDataType через разделитель «;»);
  • Description – описание свойства;
  • DescriptionLocalizeID – константа локализации описания свойства;
  • Visible – признак доступности свойства в окне схемы маршрута задачи;
  • ParentProperty – родительское свойство;
  • IsOut – признак выходного свойства. Возможные значения true и false;
  • ValueType – тип значения параметра свойства;
  • AllowedValueTypes – допустимые типы значения (строка через разделитель «;»).

Узел Property может содержать дочерние узлы:

  • ValueParamNames – корневой узел для ValueParamName (описание параметра, связанного со свойством);
  • PickValues – корневой узел для PickValue (возможное значение свойства);
  • Value – значение свойства.

Пример узла Properties:

<Properties> 
	<Property Name="TaskSubject" Type="2" Description="Тема" DescriptionLocalizeID="SYSRES_SBINTF.ROUTE_SUBJECT_PROP_DESCRIPTION" Visible="true" ParentProperty="" IsOut="false" ValueType="0" AllowedTypes="2" AllowedValueTypes="0;1;2">
		<ValueParamNames/>
		<Value>
			<Value>
				<![CDATA[{5314B05F-CF9F-4F66-99EC-24992A5FB114}0+Tg6+Xt6OUg5O7q8+zl7fLgL+fg5OD36A==]]>
			</Value>
		</Value>
	<Property Name="AccessRightsType" Type="3" Description="Тип прав на задачу" DescriptionLocalizeID="SYSRES_SBEDMSGUI.TASKFORM_ACCESS_TYPE_COMBO_BOX_LABEL" Visible="true" ParentProperty="" IsOut="false" ValueType="0" AllowedTypes="3" AllowedValueTypes="0;1;2">
		<ValueParamNames/>
		<PickValues>
			<PickValue Code="0" Name="Всем" NameLocalizeID="SYSRES_SYSCOMP.TASK_ACCESS_TYPE_ALL"/>
			<PickValue Code="1" Name="Всем участникам" NameLocalizeID="SYSRES_SYSCOMP.TASK_ACCESS_TYPE_ALL_MEMBERS"/>
			<PickValue Code="2" Name="Ручной" NameLocalizeID="SYSRES_SYSCOMP.TASK_ACCESS_TYPE_MANUAL"/>
		</PickValues>
		<Value Value="Всем участникам"/>
	</Property>
	...
</Properties>

 

Blocks – блоки типового маршрута

Содержит дочерние узлы Block со следующими атрибутами:

  • X – координата блока по оси X;
  • Y – координата по оси Y;
  • ID – идентификатор блока;
  • SystemType – базовый тип блока, принимает значение от 0 до 11 и соответствует типу TWorkflowBlockType;
  • Type – имя блока из справочника «Блоки типовых маршрутов»;
  • InputsJoinType – тип объединения входов блока (0 – «ИЛИ» или 1 – «И»);
  • IsPropertiesFixed – признак того, что значения атрибутов изменены (тут – false, а в CurrentBlocks – true).

Пример узла Blocks:

<Blocks>
	<Block X="166" Y="96" ID="0" SystemType="0" Type="" InputsJoinType="0" IsPropertiesFixed="false">
		<Properties>...</Properties>
		<Results>...</Results>
		<Ribbon>...</Ribbon>
	...
	</Block>
</Blocks>

Раздел блока содержит узлы:

  • Properties – свойств блока (аналогично узлу Properties свойств задачи);
  • Results – возможные результаты выполнения;
  • Ribbon – содержит описание ленты блока (структура будет рассмотрена ниже, на примере RouteRibbon).

Пример узла Results:

<Results>
	<Result Code="Д" Name="На доработку" Title="На доработку" NameLocalizeID="" DefaultText="На доработку" DefaultTextLocalizeID="" IsAbort="false" IsHidden="false"/>
	<Result Code="П" Name="Принято" Title="Принято" NameLocalizeID="" DefaultText="Принято" DefaultTextLocalizeID="" IsAbort="false" IsHidden="false"/>
</Results>

 

Route – связи между блоками

Атрибут ID – номер рассматриваемого блока, для которого в <Inputs> перечисляются входящие соединения, а в Outputs исходящие. Узлы Input и Output содержат атрибуты идентификатора связываемого блока ID и кода результата выполнения ResultCode. Предопределенные результаты выполнения начинаются с символа пробел: Иначе – « ELSE», Прекращено – « ABORT». Если исходящая линия связи имеет изгибы, то каждая точка изгиба сохраняется в узле <Point>.

Пример узла Route:

<Route>
	...
	<Link ID="50">
		<Inputs>
			<Input ID="0" ResultCode=""/>
			<Input ID="63" ResultCode="T"/>
			<Comment>
				<![CDATA[{5314B05F-CF9F-4F66-99EC-24992A5FB114}yO3g9+U=]]>
			</Comment>
		</Inputs>
		<Outputs>
			<Output ID="52" ResultCode=" ELSE"/>
			<Output ID="73" ResultCode="O">
				<Point X="730" Y="200"/>
				<Point X="1140" Y="270"/>
			</Output>
			<Output ID="44" ResultCode="E">
				<Point X="230" Y="310"/>
			</Output>
		</Outputs>
	</Link>
	...
</Route>

 

ExecutedBlocks – исполняемые блоки

По мере прохождения этапов ТМ содержимое узла изменяется и используется службой Workflow.

У узла ExecutedBlocks есть атрибут NextActualID число, которое будет использовано как номер нового блока.

Узел содержит дочерние узлы RouteBlock со следующими атрибутами:

  • Type может принимать два значения. "0" – блок ТМ и "1" – цикл. Цикл имеет два собственных свойства:
    • ActualID – ID цикла, на который ссылается StartCycleBlockActualID;
    • NextBlockID – ID блока с которого начинается цикл;
  • StartCycleBlockActualID – ActualID цикла в который входит данный блок, иначе "-1";
  • Iteration – номер итерации цикла, увеличивается при переходе на блок;
  • StartServer – код сервера, на котором начато выполнение блока (тут - пустое значение, но используется в узле CurrentBlocks).

Пример узла ExecutedBlocks:

<ExecutedBlocks NextActualID="18">
	<RouteBlock Type="0" ID="2" StartCycleBlockActualID="17" Iteration="0" PreviousBlockID="-1" StartServer=""/>
	<RouteBlock Type="0" ID="3" StartCycleBlockActualID="17" Iteration="0" PreviousBlockID="-1" StartServer=""/>
	<RouteBlock Type="1" ID="16" ActualID="17" NextBlockID="2" StartCycleBlockActualID="-1" Iteration="0" PreviousBlockID="-1"/>
	<RouteBlock Type="0" ID="0" StartCycleBlockActualID="-1" Iteration="0" PreviousBlockID="-1" StartServer=""/>
	<RouteBlock Type="0" ID="1" StartCycleBlockActualID="-1" Iteration="0" PreviousBlockID="-1" StartServer=""/>
</ExecutedBlocks>

 

CurrentBlocks – текущие выполняемые блоки

По мере прохождения этапов ТМ содержимое узла изменяется и используется службой Workflow.

Состав атрибутов узла RouteBlock такой же, как и в ExecutedBlocks. Хранимые значения отличаются для:

  • StartServer – код текущего сервера, значение из установки системы MB_ACurrentServer.dbo;
  • PreviousBlockID – блок с которого произошел переход.

Узел ExpectedBlocks, хранит идентификаторы ожидаемых блоков. Так, например, если из 2-х активных блоков один уже выполнен, то в его узле ExpectedBlocks будет записан ID не выполненного блока:

<ExpectedBlocks>
	<ExpectedBlock ID="5"/>
</ExpectedBlocks>

Пример узла CurrentBlocks:

<CurrentBlocks>
	<RouteBlock ID="2" StartCycleBlockActualID="18" Iteration="2" PreviousBlockID="4" StartServer="main">
		<Block X="236" Y="166" ID="2" SystemType="3" Type="AdvancedJob" InputsJoinType="0" IsPropertiesFixed="true">
			<Properties> ... </Properties>
		</Block>
		<ExpectedBlocks/>
	</RouteBlock>
</CurrentBlocks>

Содержимое узла Block, идентично дочерним узлам Block узла Blocks, но есть небольшие отличия.

Заменяются вычисляемые роли (и соответственно меняется тип с Type="13" на Type="29")

<Value Value="РуководительИнициатораЗадачи"/>		<!—было в Blocks-->
<Value Value="Administrator"/>						<!--стало в CurrentBlocks-->

Заменяются константы (и соответственно меняется тип с ValueType="3" на ValueType="0")

<!--было-->
<Value ValueLocalizeID="COMMON.DIR70C1F818_CADE_45C9_9075_F4995E6D751E"/>
<!--стало-->
<Value>
	<Value>
		<![CDATA[{5314B05F-CF9F-4F66-99EC-24992A5FB114}...]]>
	</Value>
</Value>

 

RouteActions – действия типового маршрута

Узел содержит дочерние узлы Action со следующими атрибутами:

  • AllowedJobStates – набор состояний задания, в котором действие будет доступным;
  • Caption – заголовок действия;
  • CaptionLocalizeID – строка локализации для заголовка;
  • Code – код действия (должен быть уникален внутри списка действий);
  • EditModeEnabledState – доступность в зависимости от режима редактирования;
  • EnabledWhenAttchmentSelected – признак того, что действие будет доступно только если есть выделенное вложение (значения true и false);
  • Hint – текст подсказки к действию;
  • HintLocalizeID – строка локализации для подсказки;
  • ImageName – имя иконки для действия.

Пример узла RouteActions:

<RouteActions>
	<Action Code="Agree" Caption="Согласовано" CaptionLocalizeID="BPM.DIRBLOCK_PICK_0F4E7CBF_43CB_4EB7_B080_2DE06DBD924C" Hint="" HintLocalizeID="" EditModeEnabledState="0" AllowedJobStates="0" EnabledWhenAttchmentSelected="false" ImageName="PerformJobIcon">
		<ISBLText>
			<![CDATA[ICBPYmplY3QuRm9ybS5QZXJmb3JtV2l0aFJlc3VsdCgn0e7j6+Dx7uLg7e4nKQ==]]>
		</ISBLText>
	</Action>
	...
</RouteActions>

 

RouteRibbon – лента типового маршрута

Содержит описание ленты блока. Может встречаться как в описании одного блока в узле Block, так и в описании целого маршрута. Во втором случае описание ленты содержит изменения ленты блока относительно ленты разрабатываемого блока. Узел содержится всегда, даже если для блока не настроена лента. В этом случае в узел будет записываться пустое описание.

Пример узла RouteRibbon:

<RouteRibbon>	<!-- пустое описание -->
<Value>
<![CDATA[object TSBRibbonDescription
  Tabs = <>
end
]]> 
</Value>
</RouteRibbon>

<RouteRibbon>	<!— добавлена одна кнопка -->
<Value>
<![CDATA[object TSBRibbonDescription
  Tabs = <
    item
      Name = 'MainRibbonTab'
      Inherits = True
      Groups = <
        item
          Name = 'TextBar'
          Inherits = True
          Items = <
            item
              Name = 'CustomRibbonItem5DD89430C49348E9A2434A92E0133801'
              OrdinalIndex = 2001
              Kind = 'LargeButton'
              ActionCode = 'Action0'
              ActionCategory = 'RouteActions'
            end>
        end>
    end>
end
]]>
</Value>
</RouteRibbon>

 

Заключение

В итоге, чтобы закрыть озвученный в аннотации кейс: "передать новому сотруднику все задания предыдущего", можно выполнить следующие действия:

  • Для изменения исполнителя уже стартованных заданий использовать SQL запрос;
update
	SBTaskJob
set
	Executor = < ИД пользователя >
where
	XRecID = < ИД задания >
  • Для блоков, которые ещё не выполнялись, исправления нужно вносить в XML, в узел Blocks, если исполнитель явно указан в свойствах блока. Или в узел Params, если исполнитель используется в параметрах типа «Пользователь», «Коллекция пользователей» или «Список пользователей».
<Blocks>
	<Block ...>
		<Properties>
		...
			<Property Name="PerformerName" Type="11" Description="Исполнитель" ...>
				<ValueParamNames/>
				<Value Value="Ivanov_II"/> <!--Например Ivanov_II-->
			</Property>
...

 

Другие полезные статьи по работе с XML описанием ТМ:

30
Авторизуйтесь, чтобы оценить материал.
4
Юра Халявицкий

У нас успешно используется сценарии

Смена Инициатора задачи админ

Смена Исполнителя задания Admin

Смена Инициатора задачи

Смена Исполнителя задания

Прикреплен файл: Change.zip
 

Михаил Тарасов

Судя по заключению, для созданного задания достаточно только изменить исполнителя в SBTaskJob и переместить ссылку во входящие нового пользователя. 

Достаточно ли этих изменений? Не будет ли конфликтов на WorkFlow в том, что исполнитель задания не совпадает с исполнителем в XML схеме в CurrentBlocks? Отработают ли правила на вложенную во входящие ссылку у нового исполнителя? Не нужно ли давать права на задачу?

Если проводили исследования, поделитесь тем, что знаете.

Руслан Бапин

Михаил, спасибо за интересную и нужную статью! Это очень здорово и полезно, что Вы решили собрать сведения об XML-схеме маршрута в одном месте, т.к. это недокументированная область.

Было бы интересно узнать подробности об узле ExecutedBlocks, т.к. возникает необходимость анализировать процесс выполнения задач, например, для построения отчетов о прохождении процесса согласования. А для этого иногда надо выяснить, сколько раз выполнялся тот или иной блок. Я анализировал схемы некоторых задач и возникли вот такие конкретные вопросы:

  1. Может ли система (служба Workflow) удалять дочерние узлы RouteBlock узла ExecutedBlocks?
  2. В узел ExecutedBlocks добавляются дочерние узлы RouteBlock для каждого блока схемы маршрута (независимо от того, исполнялся ли соответствующий блок или нет)?
  3. При повторном исполнении блока добавляется еще один дочерний узел RouteBlock (а не модифицируется уже имеющийся)?
  4. Каковы допустимые значения атрибута Iteration и каков смысл этих значений? Например, значение 0 означает, что данный узел создан для данного блока до его исполнения, значение 1 означает, что данный узел создан при первом исполнении данного блока, и т.д.?

(Есть еще несколько вопросов, их задам как-нибудь потом, сейчас важнее вопросы о ExecutedBlocks.)

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