Чтобы получить список элементов именно диаграммы БП, а не экземпляра (т.е. не содержимое tbl_WorkflowItem, а содержимое сервиса диаграммы БП):
надо:
1. добавить в окно LookupControl с DatasetLink'ом на датасет mds_WorkflowDiagramAction
2. для этого контрола добавить обработчик OnPrepareSelectWindow:
var Dataset = LookupControl.LookupDatasetLink.Dataset;
var DiagramUSI = GetAttribute(Self, 'DiagramUSI');
SetAttribute(Dataset, 'DiagramUSI', DiagramUSI);
}
где DiagramUSI - USI диаграммы БП (я брал из атрибутов)
3. В скрипте mds_WorkflowDiagramActionScript изменить:
var Designer = Dataset.Attributes('Designer');
var Diagram = Designer.ServiceCopy;
var DiagramItem;
на
var Designer = Dataset.Attributes('Designer');
if (!Assigned(Designer)) {
DiagramUSI = Dataset.Attributes('DiagramUSI');
if (!IsEmptyValue(DiagramUSI)) {
var Diagram = Services.GetNewItemByUSI(DiagramUSI);
} else return;
} else {
var Diagram = Designer.ServiceCopy;
}
var DiagramItem;
кстати, это я сделал для функционала перезапуска привязанных бизнес-процессов для записей:
вроде бы отрабатывает, хотя функционал все-таки админский
если кому-нибудь интересно - напишу попозже
Дмитрий, напишите, пожалуйста, для каких задач используется приведенный вами функционал, чтобы было понятнее.
"Кошкаров Андрей" написал:Дмитрий, напишите, пожалуйста, для каких задач используется приведенный вами функционал, чтобы было понятнее.
В разделе записи создаются исключительно по БП.
Но БП переделывается, глючит и т.д. В таких ситуациях возникает необходимость, не удаляя запись, перезапустить БП.
Я дал себе такую возможность :biggrin:. А приведенный функционал использую для выбора элемента (шага) БП, с которого надо начать заново. Т.е. я выбираю ActionItem, который станет активным после перезапуска.
"Андросов Дмитрий" написал:вроде бы отрабатывает, хотя функционал все-таки админский
если кому-нибудь интересно - напишу попозже
Дмитрий, Вы можете полный вариант своего решения опубликовать, нам как раз такой функционал нужен по перезапуску БП с данного элемента.
На гриде раздела лидов, которые создаются только по БП, есть кнопка:
на нее повешена следующая логика:
function amiRestartSelectedLeadsOnExecute(ActionMenuItem, Sender) { // перезапускает БП для выбранных записей var SelectedIDs = ListToArray(grdData.SelectedIDs); if (SelectedIDs.length) {RestartLeadsBP(SelectedIDs);} } function amiRestartAllLeadsOnExecute(ActionMenuItem, Sender) {// перезапускает БП для всех отфильтрованных записей var Dataset = dlData.Dataset; var SelectedIDs = [] Dataset.GoToFirst(); while(!Dataset.IsEOF) { SelectedIDs.push(Dataset('ID')); Dataset.GoToNext(); } if (SelectedIDs.length) {RestartLeadsBP(SelectedIDs);} } function RestartLeadsBP(SelectedIDs){ // SelectedIDs - массив var WorkflowItemNameWindow = Services.GetNewItemByUSI('wnd_EnterRestartWorkflowItemName'); SetAttribute(WorkflowItemNameWindow, 'NotifyObject', Self); SetAttribute(WorkflowItemNameWindow, 'SelectedIDs', SelectedIDs); // получаем USI диаграммы, к которой принадлжит привязанный к записи элемент БП var DiagramUSI = GetDatasetFieldValueByID('ds_WorkflowItem', GetDatasetFieldValueByID('ds_Leads', SelectedIDs[0], 'WorkflowItemID'), 'DiagramUSI'); SetAttribute(WorkflowItemNameWindow, 'DiagramUSI', DiagramUSI); открываем окно выбора параметров перезапуска WorkflowItemNameWindow.Show(); }
окно выглядит так:
обратите внимание: для выбора элемена БП используется базовый mds_WorkflowDiagramAction, в котором (как указано в шапке) надо изменить:
function FillDatasetFromDiagramDesigner(Dataset) { var Designer = Dataset.Attributes('Designer'); if (!Assigned(Designer)) { // это DiagramUSI = Dataset.Attributes('DiagramUSI'); // это if (!IsEmptyValue(DiagramUSI)) { // это var Diagram = Services.GetNewItemByUSI(DiagramUSI); // это } else return; // это } else { // это var Diagram = Designer.ServiceCopy; } // это var DiagramItem;
скрипт для окна:
//----------------------------------------------------------------------------- // wnd_EnterRestartWorkflowItemNameScript //----------------------------------------------------------------------------- var Data = {} ; function wnd_EnterRestartWorkflowItemNameOnClose(Window) { btnCancelOnClick(); } function btnOKOnClick(Control) { Data.MppContactID = edtOwner.Value; SendNotify(Self, MSG_OK, Data); // посылаем Notify обратно на окно грида (где и отрабатывается логика рестарта) Self.Close(); } function btnCancelOnClick(Control) { SendNotify(Self, MSG_CANCEL); // посылаем Notify обратно на окно грида (где и отрабатывается логика рестарта) Self.Close(); } function edtWFItemNameLUOnPrepareSelectWindow(LookupControl, SelectWindow) { var Dataset = LookupControl.LookupDatasetLink.Dataset; SetAttribute(Dataset, 'DiagramUSI', GetAttribute(Self, 'DiagramUSI')); } function edtWFItemNameLUOnChange(LookupControl) { var Dataset = LookupControl.LookupDatasetLink.Dataset; Data.WFItemName = Dataset('Name'); // сохраняем имя выбранного элемента БП } function wnd_EnterRestartWorkflowItemNameOnPrepare(Window) { edtWFItemNameLU.Value = null; edtWFItemNameLU.Text = null; }
получив оповещение на гриде отрабатывает:
function wnd_LeadsGridAreaOnNotify(ScriptableService, Sender, Message, Data) { var Dataset = dlData.Dataset; if (Message == MSG_OK) { if (Sender.Caption == 'wnd_EnterRestartWorkflowItemName') { var SelectedIDs = GetAttribute(Sender, 'SelectedIDs');//Data.SelectedIDs; if (!!SelectedIDs.length) { // здесь немного логике по обработке выбранного нового ответственного (для записи лида) var WorkflowItemName = Data.WFItemName; var MppContactID = Data.MppContactID; var MppContactIDs = []; var UpdateOwner = true; if (!IsEmptyGUID(MppContactID)) { for (var i = 0; i < SelectedIDs.length; i++) { MppContactIDs[i] = MppContactID; } } else { for (var i = 0; i < SelectedIDs.length; i++) { MppContactIDs[i] = GetDatasetFieldValueByID('ds_Leads', SelectedIDs[i], 'OwnerID'); // если не выбрано - берется из текущего датасета UpdateOwner = false; } } ProcessRestartLeadsBP(SelectedIDs, WorkflowItemName, MppContactIDs, UpdateOwner); // сама функция } var RecordID = ''; for (var i = 0; i < SelectedIDs.length; i++) { RecordID = SelectedIDs[i]; RecreateDefaultRights(['tbl_Leads'], 'OwnerID', null, true, RecordID); // немаловажно, если поменяли ответственного - обновляем права на запись (функционал см здесь - _http://www.community.terrasoft.ru/blogs/9611#comment-40937) Dataset.RefreshRecord(RecordID, true); } return; } } wnd_BaseGridAreaOnNotify(ScriptableService, Sender, Message, Data); }
function ProcessRestartLeadsBP(SelectedIDs, WorkflowItemName, MppContactIDs, UpdateOwner){ // функция-обертка RestartWorkflowBySelectedRecordsInTableAndWorkflowItemName('tbl_Leads', SelectedIDs , WorkflowItemName, MppContactIDs, UpdateOwner); } function RestartWorkflowBySelectedRecordsInTableAndWorkflowItemName(TableName // название таблицы записей, на основе которых делается перезапуск , SelectedIDs // массив ИД записей , WorkflowItemName // название элемента, на который перезапустится БП , MppContactIDs // массив новых ответственных для записей (согласованный с массивом SelectedIDs ) , UpdateOwner) { // признак, что надо обновлять ответственного var CQ = GetSingleItemByCode('cq_ClearBaseOfWorkflowItemIDs'); // см ниже - много sql // по сути: зачищаем все ссылки на конкретный экземпляр БП (связанный с конкретной записью) во всех (опционально) таблицах и в этой самой записи CQ.Parameters.ItemsByName('BaseTableName').Value = TableName; CQ.Parameters.ItemsByName('IncludedString').Value = SelectedIDs.join(); CQ.Parameters.ItemsByName('Delimeter').Value = ','; CQ.Parameters.ItemsByName('AllTables').Value = true; CQ.Execute(); var WorkflowEngine = GetWorkflowEngine(); var Now = new Date(System.Now()).getVarDate(); var Dataset = GetSingleItemByCode('ds_Leads', 'RestartWF'); if (Assigned(WorkflowEngine) && !IsEmptyGUID(WorkflowItemName)) { // не знаю почему IsEmptyGUID, наверно я имел ввиду IsEmptyValue )) for (var i = 0; i < SelectedIDs.length; i++) { // запускаем новый экземпляр БП, с параметром IsFake = true (который провоцирует остановку в самом начале - см. элемент "Задержка" (см. скрин ниже) var WF_ID = WFStartByUSI('wd_LeadsMain' ,['LeadsID', 'MppContactID', 'IsFake'] ,[SelectedIDs[i], MppContactIDs[i], true]); // принудительно запускаем БП с нужного нам элемента (с нужными нам параметрами) var WorkflowItemWF_ID = StartWorkflowItem(WF_ID, WorkflowItemName ,['LeadsID', 'MppContactID', 'IsFake'] ,[SelectedIDs[i], MppContactIDs[i], false]); // и обновляем WorkflowItemID для выбранной записи ApplyDatasetFilter(Dataset, 'ID', SelectedIDs[i], true); Dataset.Open(); Dataset.Edit(); if (!!UpdateOwner) { Dataset('OwnerID') = MppContactIDs[i]; } Dataset('WorkflowItemID') = !IsEmptyGUID(WorkflowItemWF_ID) ? WorkflowItemWF_ID : null; Dataset.Post(); Dataset.Close(); } } }
function WFStartByUSI(WorkflowUSI, ParamNames, ParamValues) { var WorkflowEngine = GetWorkflowEngine(); var Now = new Date(System.Now()).getVarDate(); var Params = WFArrayToParams(ParamNames, ParamValues); var ID; /*if (!!NoReturn) { if (Assigned(Params)) { WorkflowEngine.StartWorkflow(WorkflowUSI, Now, Params); } else { WorkflowEngine.StartWorkflow(WorkflowUSI, Now); } return; }*/ if (Assigned(Params)) { ID = WorkflowEngine.StartWorkflow(WorkflowUSI, Now, Params); } else { ID = WorkflowEngine.StartWorkflow(WorkflowUSI, Now); } return ID; } function StartWorkflowItem(WorkflowID, ItemName, ParamNames, ParamValues) { var WorkflowEngine = GetWorkflowEngine(); var Now = new Date(System.Now()).getVarDate(); var Params = WFArrayToParams(ParamNames, ParamValues); var ID; if (Assigned(Params)) { ID = WorkflowEngine.StartWorkflowItem(WorkflowID, ItemName, Now, Params); } else { ID = WorkflowEngine.StartWorkflowItem(WorkflowID, ItemName, Now); } return ID; }
cq_ClearBaseOfWorkflowItemIDs
declare @BaseTableName varchar(250) = :BaseTableName declare @TableName varchar(250) = :TableName declare @IncludedString nvarchar(4000) = :IncludedString declare @delimeter1 nvarchar(4000) = :Delimeter declare @AllTables int = :AllTables -- опция для обработки всех таблиц с полем WorkflowItemID if (@AllTables = 1) begin -- получаем список всех таблиц с полем WorkflowItemID declare tc cursor local fast_forward for select name from SYSOBJECTS where ID in (SELECT id FROM SYSCOLUMNS WHERE NAME='WorkflowItemID') and xtype = 'U' and name != @BaseTableName open tc end else begin -- либо берем из параметра declare tc cursor local fast_forward for select name from (values (@TableName)) as X(name) open tc end while (1=1) begin fetch next from tc into @TableName if @@fetch_status = -1 break if @@fetch_status = -2 continue print @IncludedString print @TableName exec(N' -- для парсинга IncludedTablesString start -- см _http://www.community.terrasoft.ru/blogs/10130 declare @input_str nvarchar(4000) = ''' + @IncludedString + ''' declare @IncludedTablesStringTable table (Code uniqueidentifier) declare @IncludedTablesStringCode nvarchar(4000) declare @delimeter nvarchar(4000) = '''+@delimeter1+''' declare @pos int = 0 declare @len int = LEN(@input_str + cast(2 as varchar)) - 1 declare @lend int = LEN(@delimeter + cast(2 as varchar)) - 1 declare @oldpos int = 0 declare @substr nvarchar(4000) while (@pos <= @len) begin set @substr = SUBSTRING(@input_str, @pos, @lend) if (@substr = @delimeter or @pos = @len) begin set @substr = SUBSTRING(@input_str, @oldpos, @pos - @oldpos + case when (@pos = @len) then 1 else 0 end ) insert into @IncludedTablesStringTable (Code) values (@substr) set @pos = @pos + @lend set @oldpos = @pos continue end set @pos = @pos + 1 end -- для парсинга IncludedTablesString end -- собственно логика зачистки ссылок на БП update ' + @TableName + ' set WorkflowItemID = null where WorkflowItemID in (select ID from tbl_WorkflowItem where WorkflowID in (select WorkflowID from tbl_WorkflowItem where ID in (select WorkflowItemID from '+ @BaseTableName + ' where ID in (select Code from @IncludedTablesStringTable) ) ) ) update ' + @BaseTableName + ' set WorkflowItemID = null where ID in (select Code from @IncludedTablesStringTable) ') end close tc deallocate tc
не претендую на изящность, делалось по пути и кусками))
в любом случае оно проще, чем кажется