Добрый день.
Столкнулись с таким странным поведением в bpm'online версии 7.2 - есть процесс, который запускается на изменение поля у объекта, потом кое-что меняется и запускается таймер для задержки, и после этого читается измененный объект и проверяем его поля, после чего выходим. И почему-то код отрабатывает только до таймера, а после этого ничего не происходит. Сужу по логам и по тому какой результат ожидаю.
При этом на другом сайте аналогичный процесс отрабатывает корректно.
Можете подсказать в чем может быть дело, куда копать, куда смотреть?
Схема процесса:

Нравится

12 комментариев

Здравствуйте!

Поищите причину в логах сервера. По умолчанию они хранятся в C://Windows/Temp/bpmonline.

Вам необходимы логи Quartz.

Как раз проблема в том, что в логах есть только что-то наподобие нижеуказанного, но про нужный процесс ничего.
Хотя как я понимаю должны быть строчки Execute - ProcessStart и Execute - ProcessFinish. Это есть, но для другого процесса.

2015-09-29 10:53:21,562 [15264] INFO  USER Quartz.Impl.AdoJobStore.JobStoreTX Instantiate - JobStoreTX initialized.
2015-09-29 10:53:21,578 [15264] INFO  USER Quartz.Core.QuartzScheduler Initialize - Scheduler meta-data: Quartz Scheduler (v2.1.2.400) 'BPMonlineQuartzScheduler' with instanceId 'auto'
  Scheduler class: 'Quartz.Core.QuartzScheduler' - running locally.
  NOT STARTED.
  Currently in standby mode.
  Number of jobs executed: 0
  Using thread pool 'Quartz.Simpl.SimpleThreadPool' - with 3 threads.
  Using job-store 'Quartz.Impl.AdoJobStore.JobStoreTX' - which supports persistence. and is clustered.
 
2015-09-29 10:53:21,579 [15264] INFO  USER Quartz.Impl.StdSchedulerFactory Instantiate - Quartz scheduler 'BPMonlineQuartzScheduler' initialized
2015-09-29 10:53:21,579 [15264] INFO  USER Quartz.Impl.StdSchedulerFactory Instantiate - Quartz scheduler version: 2.1.2.400
2015-09-29 11:17:37,676 [8480] DEBUG USER Quartz.Impl.AdoJobStore.StdRowLockSemaphore ObtainLock - Lock 'TRIGGER_ACCESS' is desired by: 
2015-09-29 11:17:37,796 [8480] DEBUG USER Quartz.Impl.AdoJobStore.StdRowLockSemaphore ExecuteSQL - Lock 'TRIGGER_ACCESS' is being obtained: 
2015-09-29 11:17:37,799 [8480] DEBUG USER Quartz.Impl.AdoJobStore.StdRowLockSemaphore ExecuteSQL - Lock 'TRIGGER_ACCESS' is being obtained: 
2015-09-29 11:17:37,800 [8480] DEBUG USER Quartz.Impl.AdoJobStore.StdRowLockSemaphore ObtainLock - Lock 'TRIGGER_ACCESS' given to: 
2015-09-29 11:17:40,027 [8480] DEBUG USER Quartz.Impl.AdoJobStore.StdRowLockSemaphore ReleaseLock - Lock 'TRIGGER_ACCESS' returned by: 
2015-09-29 11:20:00,889 [BPMonlineQuartzScheduler_Worker-1] INFO  USER Terrasoft.Core.Scheduler.RunProcessJob Execute - ProcessStart [processSchemaName:ContactProcess, processElementUId , userName:USER, workspaceName:Default]
2015-09-29 11:21:03,648 [BPMonlineQuartzScheduler_Worker-1] INFO  USER Terrasoft.Core.Scheduler.RunProcessJob Execute - ProcessFinish [processSchemaName:ContactProcess, processElementUId , userName:USER, workspaceName:Default]
2015-09-29 11:21:51,604 [10724] DEBUG USER Quartz.Impl.AdoJobStore.StdRowLockSemaphore ObtainLock - Lock 'TRIGGER_ACCESS' is desired by: 
2015-09-29 11:21:51,606 [10724] DEBUG USER Quartz.Impl.AdoJobStore.StdRowLockSemaphore ExecuteSQL - Lock 'TRIGGER_ACCESS' is being obtained: 

Если про процесс ничего не указано в данной таблице, то необходимо проверить доходит ли процесс до элемента "Таймер".

В том-то и дело, что до таймера стоит блок сценария, в котором пишутся логи. Т.е. процесс запускается, но уже потом я не вижу, что он работает после таймера. Словно процесс и не попадает в очередь к quartz.
Если вы подскажите, в какой таблице можно посмотреть запланированные процессы к выполнению или подскажите где почитать про это, буду весьма признателен. Так как уже голову сломал, что собственно не так. И почему на одном сервере это работает, а на другом тоже самое нет.

Здравствуйте, Александр. Процессы, запускающиеся по расписанию и содержащие таймер, записываются в таблицу qrtz_triggers.

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

2015-09-30 16:40:40,227 [BPMonlineQuartzScheduler_Worker-2] INFO  user Terrasoft.Core.Scheduler.RunProcessJob Execute - ProcessStart [processSchemaName:, processElementUId 743f3d6f-802f-4d9d-9fe5-3064f62a35ed, userName:userName, workspaceName:Default]
2015-09-30 16:40:44,816 [BPMonlineQuartzScheduler_Worker-2] INFO  user Terrasoft.Core.Scheduler.RunProcessJob Execute - ProcessFinish [processSchemaName:, processElementUId 743f3d6f-802f-4d9d-9fe5-3064f62a35ed, userName:userName, workspaceName:Default]

И в списке по запросу  select distinct TRIGGER_NAME from qrtz_triggers если судить из названий, то я не вижу своего процесса. Может быть есть какая-то иная таблица, или проблема в том, что судя по логу не установлено поле processSchemaName, но как его установить? Откуда его берет процесс?

Поставьте журналируемый элемент "Чтение данных" перед таймером. Запустите процесс повторно. Процесс дошел до чтения данных?

Не понял, что имеется ввиду под "журналируемый элемент "Чтение данных""?
Если речь о элементе загрузки объекта, то на мой взгляд это не корректно. Так как за время задержки по таймеру, объект может измениться. Замечу, что без таймера процесс отрабатывает и на сервере, где с тамером не работает. Т.е. вся проблема когда добавляем таймер.
Для проверки наличия джобов, сделал ветку в которой с задержкой по Sleep опрашивалась таблица qrtz_triggers, но своей джобы я там не увидел. Процесс выглядит так:
Что еще можно сделать, для понимая ситуации?

1) Добавьте "Чтение данных" перед таймером. У элемента "Чтение данных" должен быть установлен признак "Журналировать" (в свойствах элемента)
2) Запустите процесс
3) Сделайте скриншот диаграммы процесса в журнале процессов и опубликуйте его здесь, пожалуйста.

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

Exception Message: Элемент с идентификатором "0d4daf80-dbef-4fef-9c8d-2e942b0a9965" не найден
Exception Type: Terrasoft.Common.ItemNotFoundException
Exception Source: Terrasoft.Core
 
Exception Stack Trace:
   at Terrasoft.Core.ManagerItemCollection`1.GetByUId(Guid uid)
   at Terrasoft.Core.Manager`2.GetInstanceByUId(Guid uid)
   at Terrasoft.WebApp.MainPageEventsProcess`1.InitScriptTaskExecute(ProcessExecutingContext context)
   at Terrasoft.Core.Process.ProcessFlowElement.Execute(ProcessExecutingContext context)
   at Terrasoft.WebApp.MainPageEventsProcess`1.ProcessQueue(ProcessExecutingContext context)
   at Terrasoft.WebApp.MainPageEventsProcess`1.OnExecuted(Object sender, ProcessActivityAfterEventArgs e)
   at Terrasoft.Core.Process.ProcessFlowElement.OnExecuted(ProcessActivityAfterEventArgs e)
   at Terrasoft.Core.Process.ProcessFlowElement.Execute(ProcessExecutingContext context)
   at Terrasoft.WebApp.MainPageEventsProcess`1.ProcessQueue(ProcessExecutingContext context)
   at Terrasoft.WebApp.MainPageEventsProcess`1.ThrowEvent(ProcessExecutingContext context, String message)
   at Terrasoft.UI.WebControls.PageSchemaUserControl.ThrowEvent(String message)
   at Terrasoft.UI.WebControls.Controls.PageContainer.LoadFromAssembly()
   at Terrasoft.UI.WebControls.Controls.PageContainer.LoadUserControl()
   at Terrasoft.UI.WebControls.Controls.PageContainer.OnInit(EventArgs e)
   at System.Web.UI.Control.InitRecursive(Control namingContainer)
   at System.Web.UI.Control.InitRecursive(Control namingContainer)
   at System.Web.UI.Control.InitRecursive(Control namingContainer)
   at System.Web.UI.Control.InitRecursive(Control namingContainer)
   at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

И судя по всему эта страница вообще не работала изначально, просто раньше к ней как-то ни кто не обращался.
Может быть вы подскажите куда смотреть в базе, в какую таблицу? В таком случае смогли бы выгрузить диаграмму.

Александр, смотреть нужно в SysProcessLog. Очень сложно понять в чем проблема. Предлагаю Вам зарегистрировать обращение, оправив письмо по адресу support [at] terrasoft.ru, приложив логи сервера для более детального анализа.

Спасибо за ответы. К сожалению в таблице SysProcessLog никакой ценной информации не обнаружил :'(
И после обсуждения и обдумывания пришлось отказаться от таймера, и реализовать это через потоки с задержкой. По крайней мере, это работает. Жаль только, что приходится столько времени тратить на "борьбу" с bpm.

Показать все комментарии

Добрый день, подскажите что я делаю не так.
Первая задача: при квалификации лида необходимо передавать в поле (MyValue), созданное в замещающем объекте - "1", по умолчанию стоит "0", создал замещающую клиентскую схему для LeadQualificationPageV2, переписал метод createAccountInsertQuery добавив в него следующую строку

createAccountInsertQuery: function() {
...
insert.setParameterValue("MyValue", "1", Terrasoft.DataValueType.TEXT);
return insert;

но при Квалификации лида в данное поле ничего не проставляется, а ставится значение по умолчанию "0".
Вторая задача: при появлении активности с типом E-mail необходимо создавать лида, по этому лиду должен начинаться БП, стартовым сигналом для которого является появление нового лида. Для замещающего объекта "Активности" создал процесс на событие при добавлении записи, в него добавил скрипт
var insert = new Insert(UserConnection).Into("Lead")
  .Set("LeadName", Column.Const(title))
  .Set("Contact", Column.Const(title))
  .Set("StatusId", Column.Const(status))
  .Set("LeadTypeStatusId", Column.Const(lead))
  .Set("QualifyStatusId", Column.Const(qualify))
  .Set("Commentary", Column.Const(body))
  .Execute();

все хорошо, Лид добавляется как необходимо, но БП почему то не запускается.
Третья задача: поставить таймер в БП на несколько дней, сначала повторять действие через каждый день, 3 дня подряд, потом через 2 недели еще раз каждый день 3 дня подряд. Вопрос в том есть ли вообще возможность задать такие условия и как в принципе поставить таймер который будет приостанавливать выполнение процесса на одни сутки, нашел там функции День(), но они ожидают переменной datetime следовательно им надо какую то конкретную дату указывать, что в данном случае не подходит, есть ли функция вроде Час()?
timer

Версия 7.4.0.2628

Нравится

11 комментариев

Со второй задачей разобрался, спасибо Дмитрию. Остались первая и третья задачи

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

Здравствуйте, Олег.

По Вашему первому вопросу - в процессе квалификации лида, попробуйте в режиме отладки убедиться, что ваш метод createAccountInsertQuery() вызывается и корректно отрабатывает.

По вопросу №3 Вам необходимо в случае использования элемента БП "Таймер" реализовать ветвление БП с помощью условных потоков, чтобы реализовать необходимый Вам алгоритм. Или же реализовать запуск БП по необходимому Вам расписанию с помощью планировщика Quartz, используя рекомендации SDK

Еще раз проверил квалификацию, перенес в начало метода createAccountInsertQuery()

insert.setParameterValue("MyValue", "1", Terrasoft.DataValueType.TEXT);

начало работать.

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

P.S. Возник еще вопрос как реализовать и возможно ли подобное
бп
Необходимо создавать звонок каждый день, в течении трех дней, если результат "Не удалось дозвониться" три дня подряд, тогда менять значение таймера на две недели и через две недели опять каждый день три дня подряд

Здравствуйте, Олег!

Если необходимо задавать в планировщик именно промежуток времени, то Вам можно воспользоваться Крон-триггером (SDK).
Касательно P.S. - это тоже реализуемо с помощью Quartz, но, к сожалению, готовых примеров нет.

Спасибо, но решил вопрос иначе - задав параметр в процессе который вставляется в значение таймера и при каждом повторении просто его пересчитываю.
Возник вопрос по поводу квалификации лида:
У лида добавлены поля "Фамилия", "Имя", "Отчество" при квалификации лида необходимо чтобы эти поля переносились в контакт, если создается новый контакт на основе лида. Переопределил метод

createContactInsertQuery: function() {
    var insert = this.Ext.create("Terrasoft.InsertQuery", { rootSchemaName: "Contact" });
    insert.setParameterValue("Id", Terrasoft.generateGUID(), Terrasoft.DataValueType.GUID);
    var contact = this.get("Contact");
    if (contact) {
        insert.setParameterValue("Name", contact, Terrasoft.DataValueType.TEXT);
    }
    var givenname = this.get("UsrGivenName");
    if (givenname) {
        insert.setParameterValue("GivenName", givenname, Terrasoft.DataValueType.TEXT);
    }
    var surname = this.get("UsrSurname");
    if (surname) {
        insert.setParameterValue("Surname", surname, Terrasoft.DataValueType.TEXT);
    }
    ...
    return insert;

Но все равно если у лида не указано поле "Фамилия" а указано только "Имя", создается контакт но поле "Имя"(UsrGivenName) из лида вставляется в поле "Фамилия" контакта.
В чем может быть проблема, разве не в этом методе идет назначение столбцов для новой записи в таблице контактов?

Здравствуйте, Олег!

Уточнил у коллег из департамента разработки, переопределив данный метод, Вы не решите поставленную Вами задачу. Если необходимо переносить данные полей лида, после его квалификации в контакт, то это проще всего реализовать помощью БП. Пример процесса на скриншоте.

Добрый вечер Сергей,
Подскажите как тогда сделать ветвление в зависимости от того как был квалифицирован лид - как контакт или как контрагент. Элемент изменения данных ведь умеет обращаться только к однотипным объектам, следовательно нужно как то реализовать логику ветвления. Понятно что необходимо через исключающее или, но какие условия там необходимо прописать чтобы ветка срабатывала?

Здравствуйте, Олег!

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

Но при желании можно и в одном.

Схематически будет выглядеть следующим образом:

http://i65.fastpic.ru/big/2015/0124/e8/47d5ea3b3c4013b04f7766b1180135e8.png

В условиях стартового сигнала:

Условие:
Состояние:
Квалифицирован как новый или Квалифицирован как Существующий

Должна быть изменена любая колонка из списка:
Квалифицирован как контакт или Квалифицирован как Контрагент

Условные потоки:
[#Читать данные лида.Первый элемент результирующей коллекции.Квалифицирован как контакт#] != Guid.Empty

[#Читать данные лида.Первый элемент результирующей коллекции.Квалифицирован как контрагент#] != Guid.Empty

Спасибо, только проблема в том что элемент "Изменить данные" почему то в параметрах "Читать данные" не видит мои поля, что можно сделать чтобы поля отображались?

Олег, проблема не воспроизводится в базовой версии.
Для понимания, в чем ее причина от Вас нужна информация:
1. Точная версия приложения bpm'online.
2. Скриншоты выполняемых Вами действий.
3. В какой пакет добавлено поле, зависимости этого пакета?

Показать все комментарии

Доброго времени суток, коллеги!

В разделе [Задачи] существуют такие действия как "Запустить таймер" и "Остановить таймер", пользуясь которыми можно автоматически заполнять поля "Факт. дата начала" (старт таймера), "Факт. дата завершения" (стоп таймера) и "Факт. продолжительность" (разница между датой начала и датой завершения) в карточке редактирования задачи.
Однако, если запускать таймер несколько раз, в поле "Факт. продолжительность" будет проставлен период последнего запуска таймера, когда часто необходимо суммировать время всех периодов запусков таймера.

Для реализации данного функционала, необходимо внести изменения в функцию function SetTaskActualDuration(TaskID, StartTime) скрипта scr_TaskWorkspace (Tasks \ General \ MainGrid ):
1
Код JScript:

function SetTaskActualDuration(TaskID, StartTime) {
         if (!Assigned(TasksWorkspace.TaskStopTimerUpdateQuery)) {
                   InitializeTaskStopTimerUpdateQuery();
         }
         if (TasksWorkspace.ClosedTastStatusCalc != true) {
                   TasksWorkspace.ClosedTastStatusID = GetTaskStatusIDByCode('Closed');
                   if (IsEmptyGUID(TasksWorkspace.ClosedTastStatusID)) {
                            TasksWorkspace.ClosedTastStatusID = null;
                   }
                   TasksWorkspace.ClosedTastStatusCalc = true;
         }
         var UpdateQuery = TasksWorkspace.TaskStopTimerUpdateQuery;
         var CurrentTime = new Date(System.Now());
         var Milliseconds = CurrentTime.getTime() - StartTime;
         var ActualDurationData =
                   GetDurationDataFromMilliseconds(Milliseconds);
         var ActualDurationHours = ActualDurationData.Hours;
         var ActualDurationMinutes = ActualDurationData.Minutes;
         var Parameters = UpdateQuery.Parameters;        
         var Dataset = Services.GetNewItemByUSI('ds_Task');        
         ApplyDatasetFilter(Dataset, 'ID', TaskID, true);
         Dataset.Open();
         var OldActualDuration = Dataset.Values('ActualDuration');
         Dataset.Close();                
         SetParameterValue(Parameters, 'ID', TaskID);
         SetParameterValue(Parameters, 'ActualDurationHours', ActualDurationHours);
         SetParameterValue(Parameters, 'ActualDurationMinutes', ActualDurationMinutes);
         SetParameterValue(Parameters, 'ActualDuration',
                   (Math.round(Milliseconds / 1000 / 60) + OldActualDuration));
         SetParameterValue(Parameters, 'StatusID', TasksWorkspace.ClosedTastStatusID);
         UpdateQuery.Execute();
}

Нравится

Поделиться

0 комментариев
Показать все комментарии

Здравствуйте. У меня CRM X15 версии 3.2.0.11 стандартной конфигурации. Стоят следующии задачи:
1) при создании новой задачи автоматически запускать таймер (аналогично "действия->запустить таймер", только делать это программно).
2) при закрытии задачи сделать обязательным поле "подробный результат". То есть чтобы пользователь не мог закрыть задачу, не заполнив это поле.
Как мне это сделать? Заранее большое спасибо за помощь!

Нравится

4 комментария

1)var Timer = System.CreateObject('TSWindowLibrary.Timer');
зачем его создавать , я понять немогу
2) в окне редактирования задач , на событии OnDatasetDataChange

function dlDataOnDatasetDataChange(DataField) {
if (!Assigned(DataField)) {
return;
}
var DataFieldName = DataField.Name;
if (DataFieldName == 'StatusID'){
if (DataField.Value == 'айдишник состояния выполнено' ){
dlData.Dataset.DataFields('ResultID').IsRequired = true;
} else {
dlData.Dataset.DataFields('ResultID').IsRequired = false;
}

}
}

Вместо последнего if я бы написал

dlData.Dataset.DataFields('ResultID').IsRequired = (DataField.Value == 'айдишник состояния выполнено');

Спасибо, со 2-м пунктом разобрался, а вот с первым нет. Имелось ввиду что менеджеры, когда создают задачу (чаще всего они создают ее себе сами) часто забывают запутить таймер ее выполнения со всеми вытекающими отсюда последствиями.
Руководитель отдела попросил меня, чтобы это делалось автоматически, т.к. в 90% случаев факт того, что менеджер завел задачу ознает что он уже начал ее выполнять, то есть логично было бы запускать его автоматически, а не совершать дополнительное ручное действие.

Заранее спасибо за помощь!

можно попробовать изменить под себя функцию StartTimer()
которая находится в scr_TasksWorkspace
но она может неработать для вновь созданых задачь

Показать все комментарии