На проекте может возникнуть следующий кейс: без использования механизма замещения передать новому сотруднику все ЗЗУ предыдущего. В этом случае, кроме 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 описание состоит из корневого узла Settings и 10 дочерних узлов:
<Settings>
<Event> <!--События типового маршрута-->
<StartedAskableParams> <!--Установки запрашиваемых параметров при выполнении ТМ-->
<Params> <!--Описание параметров (задаются по кнопке «Параметры»)-->
<Properties> <!--Описание свойств задачи (тема, текст, вложения...)-->
<Blocks> <!--Описание блоков типового маршрута и их свойств-->
<Route> <!--Описание связей между блоками-->
<ExecutedBlocks><!--Список всех исполняемых блоков-->
<CurrentBlocks> <!--Описание текущих выполняемых блоков-->
<RouteActions> <!--Список действий типового маршрута-->
<RouteRibbon> <!--Описание ленты типового маршрута-->
</Settings>
<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:
<StartedAskableParams>
<AskableParam Name="Документ" Required="true" Hint=""/>
<AskableParam Name="Comment" Required="false" Hint="Сопроводительная информация"/>
</StartedAskableParams>
Дочерние узлы Param содержат следующие атрибуты:
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>
Содержит несколько дочерних узлов Property c атрибутами:
Узел Property может содержать дочерние узлы:
Пример узла 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>
Содержит дочерние узлы Block со следующими атрибутами:
Пример узла Blocks:
<Blocks>
<Block X="166" Y="96" ID="0" SystemType="0" Type="" InputsJoinType="0" IsPropertiesFixed="false">
<Properties>...</Properties>
<Results>...</Results>
<Ribbon>...</Ribbon>
...
</Block>
</Blocks>
Раздел блока содержит узлы:
Пример узла 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>
Атрибут 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>
По мере прохождения этапов ТМ содержимое узла изменяется и используется службой Workflow.
У узла ExecutedBlocks есть атрибут NextActualID – число, которое будет использовано как номер нового блока.
Узел содержит дочерние узлы RouteBlock со следующими атрибутами:
Пример узла 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>
По мере прохождения этапов ТМ содержимое узла изменяется и используется службой Workflow.
Состав атрибутов узла RouteBlock такой же, как и в ExecutedBlocks. Хранимые значения отличаются для:
Узел 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>
Узел содержит дочерние узлы Action со следующими атрибутами:
Пример узла 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>
Содержит описание ленты блока. Может встречаться как в описании одного блока в узле 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>
В итоге, чтобы закрыть озвученный в аннотации кейс: "передать новому сотруднику все задания предыдущего", можно выполнить следующие действия:
update
SBTaskJob
set
Executor = < ИД пользователя >
where
XRecID = < ИД задания >
<Blocks>
<Block ...>
<Properties>
...
<Property Name="PerformerName" Type="11" Description="Исполнитель" ...>
<ValueParamNames/>
<Value Value="Ivanov_II"/> <!--Например Ivanov_II-->
</Property>
...
Другие полезные статьи по работе с XML описанием ТМ:
У нас успешно используется сценарии
Смена Инициатора задачи админ
Смена Исполнителя задания Admin
Смена Инициатора задачи
Смена Исполнителя задания
Прикреплен файл: Change.zip
Судя по заключению, для созданного задания достаточно только изменить исполнителя в SBTaskJob и переместить ссылку во входящие нового пользователя.
Достаточно ли этих изменений? Не будет ли конфликтов на WorkFlow в том, что исполнитель задания не совпадает с исполнителем в XML схеме в CurrentBlocks? Отработают ли правила на вложенную во входящие ссылку у нового исполнителя? Не нужно ли давать права на задачу?
Если проводили исследования, поделитесь тем, что знаете.
Михаил, спасибо за интересную и нужную статью! Это очень здорово и полезно, что Вы решили собрать сведения об XML-схеме маршрута в одном месте, т.к. это недокументированная область.
Было бы интересно узнать подробности об узле ExecutedBlocks, т.к. возникает необходимость анализировать процесс выполнения задач, например, для построения отчетов о прохождении процесса согласования. А для этого иногда надо выяснить, сколько раз выполнялся тот или иной блок. Я анализировал схемы некоторых задач и возникли вот такие конкретные вопросы:
(Есть еще несколько вопросов, их задам как-нибудь потом, сейчас важнее вопросы о ExecutedBlocks.)
Авторизуйтесь, чтобы написать комментарий