Добрый день, подскажите, может кто уже решал этот вопрос.

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

Место указал. Подскажите как это делается и почему не отражается. Добавил поле во всех 3-х видах мини-карточки - "Добавление" "Редактирование" и "Просмотр", но не помогло. Куда дальше смотреть не знаю.

Нравится

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

Александр, перезапуск, чистка Redis и кэша браузера не помогли?

Как именно добавили для разных видов?

Зверев Александр, Добавил через мастер раздела, в редактировании мини-карточки сначала. А затем нашёл вот такой код:  

Но и с его помощью получилось добиться лишь такого результата: 

 

То есть поле показывается, но становится не редактируемым. Но если нажать карандашик справа вверху, то там это поле показано как необходимо. Но нужно чтобы оно здесь уже работало. То есть до раскрытия полной мини-карточки.

 

Что Вы имеете в виду под «мини-версией этой мини-карточки», режим просмотра (третий в мастере)?

Если так, то зачем там вообще возможность редактирования?

У Вас проблема, что поля нет или что оно заблокировано?

 

Если открыть в мастере стандартную карточку, например, контакта, видно, что в режиме просмотра нет большинства добавленных в мастере полей, а есть разработанные кодом блоки, например, JobInfoContainer. В схеме ContactMiniPage в пакете UIv2 видно его логику:

{
	"operation": "insert",
	"name": "JobInfoContainer",
	"parentName": "MiniPage",
	"propertyName": "items",
	"values": {
		"id": "JobInfoContainer",
		"visible": {"bindTo": "isViewMode"},
		"selectors": {"wrapEl": "#JobInfoContainer"},
		"itemType": Terrasoft.ViewItemType.CONTAINER,
		"wrapClass": ["jobinfo-mini-wrap"],
		"items": [],
		"layout": {
			"column": 0,
			"row": 10,
			"colSpan": 24
		}
	}
},
{
	"operation": "insert",
	"parentName": "JobInfoContainer",
	"propertyName": "items",
	"name": "JobInViewMode",
	"values": {
		"labelConfig": {
			"visible": false
		},
		"bindTo": "JobViewValue",
		"isMiniPageModelItem": true
	}
},
{
	"operation": "insert",
	"parentName": "JobInfoContainer",
	"propertyName": "items",
	"name": "AccountInViewMode",
	"values": {
		"labelConfig": {
			"visible": false
		},
		"bindTo": "Account",
		"isMiniPageModelItem": true
	}
},
...
/**
 * Job value in view mode.
 * @type {String}
 */
"JobViewValue": {
	"dataValueType": Terrasoft.DataValueType.TEXT,
	"type": Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN
},

В них для чтения отображается либо текст обычного поля (Account), либо вычисляемого при открытии в onEntityInitialized виртуального поля JobViewValue.

 

Для мини-карточки активности, которую дорабатываете, должно быть аналогично.

 

То есть, если Вам нужен просто текст нового поля, можно добавить кодом свой блок, указав существующий элемент родительским. И там и проверять условия, и выводить текст с нужным оформлением.

 

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

 

Проверил по стандартным разделам, таких карточек просмотра с редактируемыми полями не встречается.

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

В разделе есть несколько типов страницы редактирования. Как установить условия на видимость кнопки добавления для одного из типов? В каком модуле определены данные кнопки? Заранее спасибо!

Изображение удалено.

Нравится

11 комментариев
Лучший ответ

В diff схемы реестра раздела добавляем 

{
            "operation": "merge",
            "name": "SeparateModeAddRecordButton",
            "parentName": "SeparateModeActionButtonsLeftContainer",
            "propertyName": "items",
            "values": {
                "itemType": Terrasoft.ViewItemType.BUTTON,
                "style": Terrasoft.controls.ButtonEnums.style.GREEN,
                "caption": {"bindTo": "AddRecordButtonCaption"},
                "click": false,
                "visible": {"bindTo": "IsAddRecordButtonVisible"},
                "classes": {
                    "textClass": ["actions-button-margin-right"],
                    "wrapperClass": ["actions-button-margin-right"]
                },
                "controlConfig": {
                    "menu": {
                        "items": {
                            "bindTo": "EditPages",
                            "bindConfig": {
                                "converter": function(editPages) {

                                    if (editPages.getCount() === 0) {
                                        return null;
                                    }
                                    var operationHash = {
                                        "38d26ca1-ab6a-474c-950d-f9ac9b630967": "CanAbilityToAdd1", //здесь guid это id справочника по которому определяется страница редактирования
                                        "2495b17d-2465-41cb-b625-ac36d9aef931": "CanAbilityToAdd2"
                                    };
                                    
                                    var allowedPages = [];
                                    
                                    if (this.get("CanAbilityToAdd1")) {
                                        allowedPages.push("CanAbilityToAdd1");
                                    }
                                    
                                    if (this.get("CanAbilityToAdd2")) {
                                        allowedPages.push("CanAbilityToAdd2");
                                    }

                                    for (var key in operationHash) {
                                        var hashItem = departmentToOperationHash[key];
                                        if (allowedPages.indexOf(hashItem) === -1) {
                                            editPages.collection.remove(editPages.collection.getByKey(key));
                                        }
                                    }
                                    return editPages;
                                }
                            }
                        }
                    }
                }
            }
        }
}

 

В init добавляем к примеру проверку на доступ по операции, либо другую функциональность

initCanAbilityToAdd1: function() {
                RightUtilities.checkCanExecuteOperation({
                    operation: "CanAbilityToAdd1"
                }, function(result) {
                    this.set("CanAbilityToAdd1", result);
                }, this);
            },

Добрый вечер.

Кнопки для добавления разных типов записей генерируются автоматически в зависимости от информации в таблице SysModuleEdit и поля TypeColumnValue в этой таблице.

Названия пунктов меню для разных страниц редактирования берутся из поля ActionKindCaption.

Более подробную информацию посмотрите в этом посте.

Пользовательскими настройками (без внесения дополнительных изменений в программный код) настроить видимость пункта меню в кнопке [Добавить] этого сделать не получится.

Базовая логика добавления пунктов меню для кнопки [Добавить] раздела реализована в схеме 'BaseDataView' пакета NUI.

Для реализации Вашей задачи Вы можете попробовать внести изменения в методы, которые отвечают за добавление пунктов меню в кнопку [Добавить] в Вашем разделе.

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

Зверев Александр,

Не уверенна, что разграничение прав доступа, как-то повлияет на видимость пункта меню кнопки [Добавить] для этого типа.

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

В diff схемы реестра раздела добавляем 

{
            "operation": "merge",
            "name": "SeparateModeAddRecordButton",
            "parentName": "SeparateModeActionButtonsLeftContainer",
            "propertyName": "items",
            "values": {
                "itemType": Terrasoft.ViewItemType.BUTTON,
                "style": Terrasoft.controls.ButtonEnums.style.GREEN,
                "caption": {"bindTo": "AddRecordButtonCaption"},
                "click": false,
                "visible": {"bindTo": "IsAddRecordButtonVisible"},
                "classes": {
                    "textClass": ["actions-button-margin-right"],
                    "wrapperClass": ["actions-button-margin-right"]
                },
                "controlConfig": {
                    "menu": {
                        "items": {
                            "bindTo": "EditPages",
                            "bindConfig": {
                                "converter": function(editPages) {

                                    if (editPages.getCount() === 0) {
                                        return null;
                                    }
                                    var operationHash = {
                                        "38d26ca1-ab6a-474c-950d-f9ac9b630967": "CanAbilityToAdd1", //здесь guid это id справочника по которому определяется страница редактирования
                                        "2495b17d-2465-41cb-b625-ac36d9aef931": "CanAbilityToAdd2"
                                    };
                                    
                                    var allowedPages = [];
                                    
                                    if (this.get("CanAbilityToAdd1")) {
                                        allowedPages.push("CanAbilityToAdd1");
                                    }
                                    
                                    if (this.get("CanAbilityToAdd2")) {
                                        allowedPages.push("CanAbilityToAdd2");
                                    }

                                    for (var key in operationHash) {
                                        var hashItem = departmentToOperationHash[key];
                                        if (allowedPages.indexOf(hashItem) === -1) {
                                            editPages.collection.remove(editPages.collection.getByKey(key));
                                        }
                                    }
                                    return editPages;
                                }
                            }
                        }
                    }
                }
            }
        }
}

 

В init добавляем к примеру проверку на доступ по операции, либо другую функциональность

initCanAbilityToAdd1: function() {
                RightUtilities.checkCanExecuteOperation({
                    operation: "CanAbilityToAdd1"
                }, function(result) {
                    this.set("CanAbilityToAdd1", result);
                }, this);
            },

Да, Алла права, похоже, права на запись в справочнике типов не влияют, ведь выпадающий список формируется по объекту «Страница редактирования». А он общий для всех разделов. В таком случае лучше воспользоваться доработкой по предложению Евгения.

 

Уже зарегистрирована идея  добавить возможность контролировать какой тип страницы редактирования используется какой ролью.

Полозюков Евгений Петрович,

 пытаюсь сделать что-то подобное, все проверила 10 раз, но отладчик выдает:

Uncaught (in promise) TypeError: RightUtilities.checkCanExecuteOperation is not a function

А Вы добавили в начале в квадратных скобках и параметрах ссылку на RightUtilities? Посмотреть, как это сделано, можно в других схемах, где её используют:

define("SysOperationAuditSectionV2", ["BaseFiltersGenerateModule", "SysOperationAudit", "SysOperationAuditArch",
	"RightUtilities"],
function(BaseFiltersGenerateModule, SysOperationAudit, SysOperationAuditArch, RightUtilities) {
	return {

 

Зверев Александр, да, была проблема с последовательностью схем и параметров, передаваемых в схему)

Алла Савельева,

 

Спасибо, что подсказали на тему замещения BaseDataView. Натолкнули на верный путь!

Если кому то поможет, вот проверка на доступ к просмотру указанного типа страницы. Очень коряво, но я учусь и это работает)

define("ActivitySectionV2", ["ConfigurationConstants","RightUtilities","ProcessModuleUtilities","BaseDataView"],
function(ConfigurationConstants,RightUtilities,ProcessModuleUtilities) {
	return {
		entitySchemaName: "Activity",
		details: /**SCHEMA_DETAILS*/{}/**SCHEMA_DETAILS*/,
		attributes: 
		{ 
			"UsrCanManageItTask": {
				dataValueType: this.Terrasoft.DataValueType.BOOLEAN,
				type: this.Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN,
				value: false
			}
		},
		diff: /**SCHEMA_DIFF*/[
 
			]/**SCHEMA_DIFF*/,
		methods: {
			init: function()
			{
					this.getUserSettingsOperationRight();
					window.console.log("Инициализация");
					this.callParent(arguments);
					window.console.log("Права");
 
			},
 
			initEditPages: function() {
				window.console.log("Определение кнопок начало");
 
				var enabledEditPages = new this.Terrasoft.Collection();
 
					this.callParent(arguments);
					var editPages = this.get("EditPages");
 
					window.console.log("Получение страниц");
					var flag = this.get("UsrCanManageItTask");
					this.Terrasoft.each(editPages.getItems(), function(item) {
						window.console.log("Проверка типа");
						window.console.log(item.get("Id"));
						//window.console.log(ConfigurationConstants.Activity.Type.Email);ConfigurationConstants.Activity.Type.Call
						if (item.get("Id") !== "e2831dec-cfc0-df11-b00f-001d60e938c6" &&
							item.get("Id") !== "e1831dec-cfc0-df11-b00f-001d60e938c6") {
 
							if (item.get("Id") !== "f5921924-3e81-4a5f-ae4c-5a6f1b6e7661")
							{
								enabledEditPages.add(item);
								//window.console.log("ок");
							}
							else { 
								if (flag)
								{
										enabledEditPages.add(item);
										//window.console.log("ок");
								}
							}
						}
					});
					window.console.log("Проверка типа конец");
					this.set("EnabledEditPages", enabledEditPages);
 
					window.console.log("Определение кнопок конец");
			},
 
			getFilters: function() {
						window.console.log("Добавление фильтра");
						var filters = this.callParent(arguments);
						if (!this.get("UsrCanManageItTask"))
						{
							filters.add("NotItTask", this.Terrasoft.createColumnFilterWithParameter(
							this.Terrasoft.ComparisonType.NOT_EQUAL, "Type", "f5921924-3e81-4a5f-ae4c-5a6f1b6e7661"
							));
							window.console.log("Добавление фильтра");
						}
						return filters;
			},
 
			getUserSettingsOperationRight: function() {
				//debugger;
				var operationsToRequest = ["UsrCanManageItTask"];
				//operationsToRequest.push("UsrCanManageItTask");
				window.console.log("Права");
 
				RightUtilities.checkCanExecuteOperations(operationsToRequest, function(result) {
					if (result) {
						this.set("UsrCanManageItTask", result.UsrCanManageItTask);
						window.console.log("Права на ит-задачи: "+result.UsrCanManageItTask);
					}
				}, this);
			}
		}
 
	};
});

 

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

Как обновить "Панель действий" не перезагружая страницу при создании активности.

Пример ситуации:

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

Ну или как часто бывает у меня - Создается продажа из карточки, процесс начался, и база очень долго создает активность (да, на это бывает уходит минуты две, но это уже вопрос по работе с СУБД Oracle), но пользователь уже зашел в карточку, и когда активность все же создалась то на панели действий ее нет так как она создалась когда у кейса выбрана стадия и панель действий загрузилась уже

Нравится

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

Пример ситуации:

Менеджер сидит и на втором мониторе смотрит фильм, 

Отличное начало.laugh

 

Обычно обмен информацией  между сервером и открытыми в браузере страницами делается при помощи ClientMessageBridge. С его помощью можно порождать сообщения, которые отправляются через sandbox.

 

Конкретно с панелью действий работают сообщения ReloadDashboardItems (отправляется из BaseMiniPage) и ChangeDashboardTab (из ActivityMiniPage):

/**
 * Publishes events after entity save.
 * @protected
 * @param {Function} [callback] Callback-function.
 * @param {Object} [scope] Callback execution context.
 */
publishOnSaveEvents: function(callback, scope) {
	this.sandbox.publish("ReloadDashboardItems", {
		id: this.get("Id")
	});
	this.Ext.callback(callback, scope || this);
},
/**
 * @inheritdoc BaseMiniPage#close
 * @override
 */
close: function() {
	if (this.destroyed) {
		return;
	}
	this.sandbox.publish("ChangeDashboardTab", null);
	this.callParent(arguments);
},

 

Они принимаются в BaseActionsDashboard:

/**
 * Subscribe on events of sandbox.
 * @protected
 */
subscribeSandboxEvents: function() {
	var sandbox = this.sandbox;
	sandbox.subscribe("ReloadDashboardItems", function() {
		this.onReloadDashboardItems();
	}, this);
	sandbox.subscribe("ChangeDashboardTab", function(tabName) {
		this.setActiveTab(tabName);
	}, this);
},

Далее срабатывают обработчики в этой же или дочерних схемах.

 

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

 

Зверев Александр,

Но как это сделать из бизнес процесса?

Я создал замещение объекта "Активность", в нем добавил сообщение после создания записи. Создал событийный процесс что реагирует на это сообщение, в нем создал класс с колонкой Id (так как в подпищике смотрю эту колонку ждет)

	public class idNumberOpportunity
    {
		public Guid Id { get; set; }
    }

проверил что колонка "Продажа" не пуста

Entity.GetTypedColumnValue<Guid>("OpportunityId") != Guid.Empty

и в сценарии запустил код преобразовав сообщение в нужный вид преобразовав в Json формат (на выходе в js вышло так { "Id": "22345200-abe8-4f60-90c8-0d43c5f6c0f6"})

var userConnection = Entity.UserConnection;
var KtIdOpportunuty = new idNumberOpportunity();
KtIdOpportunuty.Id = Entity.GetTypedColumnValue<Guid>("OpportunityId");
MsgChannelUtilities.PostMessage(userConnection, "ReloadDashboardItems", JsonConvert.SerializeObject(KtIdOpportunuty));
return true;

Но видимо подписка так не срабатывает.

Что я не так делаю, подскажите?

Попробуйте поставить отладчик в onReloadDashboardItems, так будет видно, доходит ли Ваше сообщение и чем отличается от настоящего.

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

Может кто сталкивался с таким.

Выбирая ответственного в каком либо разделе мы видим контакты сотрудников но там так же сотрудники у которых пользователь активен и те у кого не активен.

Можно зафильтровать добавив в замещаемом модуле код для атрибута

"Owner": {
	"dataValueType": Terrasoft.DataValueType.LOOKUP,
	"lookupListConfig": {
		filter: function() {
			var filterGroup = Ext.create("Terrasoft.FilterGroup");
			filterGroup.add("IsUser",
				Terrasoft.createColumnIsNotNullFilter("[SysAdminUnit:Contact].Id"));
			filterGroup.add("IsActive",
				Terrasoft.createColumnFilterWithParameter(
					Terrasoft.ComparisonType.EQUAL,
					"[SysAdminUnit:Contact].Active",
					true));
			return filterGroup;
		}
}

В продаже это нормально сработало, но в активностях не как не хочет работать фильтр.

Может кто в курсе почему?

Но вообще было бы не плохо сделать это глобально конечно, что бы ответственных можно было добавить только активных пользователей, но я такого не нашел

Нравится

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

Александр, может, в карточке активности в одном из пакетов есть своя логика на этом поле и она мешает Вашей?

Попробуйте посмотреть, какой запрос идёт в одном и другом случае. Сначала — запрос от браузера к веб-сервису, его можно увидеть в «Инструментах разработчика». Если не поможет понять и сайт развёрнут локально, можно запустить SQL-профайлер и посмотреть запросы уже на уровне базы.

Зверев Александр,

Проверил все наследования - только в ActivityPageV2 в NUI rfgtnt есть логика через атрибут

"Owner": {
	dataValueType: Terrasoft.DataValueType.LOOKUP,
	lookupListConfig: {filter: BaseFiltersGenerateModule.OwnerFilter}
}

и наследование идет от модуля что наследовался от выше указанного в NUI пакете. У себя в замещенном модуле его и заместил

Теперь попробуйте посмотреть запрос. Если Ваш фильтр идёт одновременно с этим и их условия мешают, это должно быть видно.

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

Добрый день,

 

Хочу создать бизнес-процесс "Отпуск". Суть в том, что сотрудник, уходя в отпуск запускает данный процесс, и на время его отсутствия активности передаются его заместителю.

 

Имеется "Автогенерируемая страница", в которой 4 поля (Отправитель, Получатель, Дата начала, Дата завершения). 

  1. Отправитель - сотрудник, уходящий в отпуск
  2. Получатель - заместитель
  3. Дата начала - с какого дня начинают передачу активностей на заместителя
  4. Дата завершения - когда закончить передачу и завершить бизнес-процесс.

 

Хотел реализовать через Сигнал, но в него не получается передавать значения. А если делать Сигнал на просто Добавление активности, без каких-либо условий, то получается бизнес-процесс постоянно работает, и в итоге выдает ошибку, что максимальное количество повторения превышено.

Нравится

16 комментариев
Лучший ответ

_KSL_,

 

В таком случае Вам нужно следующее.

1. В срм хранить информацию об отпусках сотрудников, например, реализовать деталь в разделе 'Сотрудники'. Структура её может быть следующей - сотрудник, дата начала отпуска, дата завершения отпуска, кому делегировать задачи. Для избежания путаницы я бы не давала сотрудникам самостоятельно вносить эту инфрмацию. Логично, что это должен делать либо ответственный за отпуска, либо HR-менеджер, либо бухгалтер.

2. Реализовать процесс, который будет автоматически запускаться по расписанию раз в сутки, когда нагрузка на систему минимальна, например, ночью или ранним утром. Данный процесс будет проверять, есть ли в отпусках сотрудники и актуализировать ответственных по их задачам.

Может быть проще использовать уже готовый бизнес-процесс по делегированию прав или модифицировать его? https://marketplace.terrasoft.ru/template/delegirovanie-prav-dostupa-na…

Сигнал не нужен, ведь данный БП запускается вручную.
После автогенерируемой страницы читаем первую запись Activity с нужными параметрами (от-до, где Ответственный = Сотрудник, ну и задача еще не завершена).
Если такая запись найдена (Id!=Guid.Empty), то модифицируем Activity, устанавливая Ответственный = Заместитель.
И снова возвращаемся к чтению записи Activity.

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

И, возможно, подумать, а как возвращать ещё не выполненные задачи после отпуска

Владимир Соколов,

 

Спасибо за ваши ответы.

 

Но проблема заключается в том, что активности могут быть еще не созданы. Если активности имеются, то да, без проблем можно процесс заменить ответственного.

Даже если будем возвращаться опять к чтению, то получается происходит постоянно чтении Activity, и возвращаемся в итоге к ошибке максимальное количество повторений.

_KSL_,

 

В таком случае Вам нужно следующее.

1. В срм хранить информацию об отпусках сотрудников, например, реализовать деталь в разделе 'Сотрудники'. Структура её может быть следующей - сотрудник, дата начала отпуска, дата завершения отпуска, кому делегировать задачи. Для избежания путаницы я бы не давала сотрудникам самостоятельно вносить эту инфрмацию. Логично, что это должен делать либо ответственный за отпуска, либо HR-менеджер, либо бухгалтер.

2. Реализовать процесс, который будет автоматически запускаться по расписанию раз в сутки, когда нагрузка на систему минимальна, например, ночью или ранним утром. Данный процесс будет проверять, есть ли в отпусках сотрудники и актуализировать ответственных по их задачам.

Алла Савельева,

Спасибо за ответ 

 

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

_KSL_,

А что мешает в том случае, если даты отпуска изменятся, откорректировать их в срм?

В любом случае, чтобы система могла выполнять какие-то действия, для неё нужно вносить вводные данные.

Давайте начнем с начала - опишите подробно, что нужно реализовать в срм и на каком этапе у Вас возникли сложности.

Алла Савельева,

 

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

 

Сотрудник, который уходит в отпуск, должен запустить данный процесс. При запуске открывается "Автогенерируемая страница", в который имеется 4 поля (Отправитель - сотрудник, уходящий в отпуск, Получатель - кому будем переназначать активность, Дата начала и Дата завершения - с какого и до какого чисел будем переназначать).

 

Далее происходит чтение данных с объекта "Активность" и изменение данных "Активность" на основании условий, т.е. Ответственный = Отправитель, Дата завершения>Дата создания >= Дата начала. 

 

Но тут возникает проблема происходит постоянное чтение данных и в результате выдает ошибку, что Превышено максимальное количество повторений. 

 

Пытался избежать превышения повторений с помощью Обработки таймера, но почему чтение данных из Активность происходит долго и затем изменение данных не происходит. Якобы чтение не прошло и новый активностей не было.

 

Через делегирование прав не могу реализовать, т.к. Ответственный не меняется. А получателю придется самому искать задачи.

 

Давайте разделим непонятность выбора алгоритма и сложности в конкретной программной реализации.

 

Если Вы хотите обработать один раз существующие задачи сотрудника, то данные об отпуске хранить не надо. А если же хотите передавать и новые задачи, которых ещё нет, то без хранения не обойтись.

 

Если у Вас при чтении активностей получается максимальное количество повторений, то, скорее всего, что-то не учли в условии и не исключаете из выборки уже обработанные записи, из-за чего перебор записей продолжается всё время.

Зверев Александр,

 

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

 

Правильно ли я понял, что я должен хранить к примеру в справочнике данные по отпускам(Сотрудник, Заместитель, Дата начала отпуска, Дата завершения).

И затем запускать процесс, который будет в определенное время менять Ответственного.

 

Но тогда не совсем понимаю как нужно будет организовать процесс.

Как Вы можете переназначит новые, их же ещё нет?

Если делаете логику на моменте создания или регулярно по планировщику, то нужно где-то брать информацию, у кого, на кого и с какого по какое отпуск.

Зверев Александр,

 

Я пытался делать через Автогенерируемую страницу, в ней было 4 поля у кого, кому, начало, завершение. 

 

Из полей Автогенерируемой страницу данные переходили в чтение данных, как условия (Ответственный=у кого, Завершения>Дата создания>=Начало). Далее шло изменение данных с такими же условиями, но меняли Ответственный=кому. Далее шел условный поток, в  котором сравнивалась текущая дата с завершением. Если текущая дата < Завершения, то возвращается к чтению.

 

Но у меня получалось так, что на процессе чтения данных процесс зависал либо длительное время обработка происходила, и в итоге новые активности не читал, и соответственно, т.к. он из не читал, Ответственный не менялся.

 

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

Сначала попытайтесь понять, что вы вообще хотите сделать. Если задач ещё не существует, то Вы их не вычитаете и не измените.

 Если текущая дата < Завершения, то возвращается к чтению

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

_KSL_,

Если у Вас версия on-site Вы можете запустить SQL profiler и отследить запрос, который идет в базу, и понять, почему происходит зацикливание.

 

Покажите код, каким образом Вы реализовали, установку ответственных в задачах в Вашем бизнес-процессе.

Алла, он просто нарисовал в БП цикл, надеясь, что он будет постоянно до даты конца отпуска крутиться и обрабатывать появляющиеся задачи. Но так нельзя, количество повторений ограничено, а до того всё зависнет.

Зверев Александр,

Ясно. Ну, ты же, знаешь, есть старая привычка докопаться до сути вопроса)))

Тут профайлер не поможет, это будет видно на диаграмме выполнения процесса. В принципе, если с таймером и всё сделать правильно, то даже будет работать, хотя подход необычный.

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

Решал ли кто-то задачу смена типа результата активности? Поделитесь опытом.

Это цвет покраски кнопок результатов активности в задачах по БП.

Нравится

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

В справочнике Результат Активности, есть 3 категории.
В зависимости от того, какая категория указана, такой цвет кнопки и будет.
Нейтральный - серый
Отрицательный - красный
Успех - зеленый

 В коде зашиты только эти три цвета и это касается задач созданных через элемент Выполнить задачу в БП

Литвинко Павел,

это прозрачно.Может можешь подсказать где зашито?

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

Как можно определить, как создана Активность - вручную пользователем или автоматически системой?
Посмотрел параметр Process Item, но он не у всех процессных активностей заполнен

Нравится

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

Если в существующих полях никаких различий нет, можно добавить в объект новое поле, в карточку не выводить визуально, но заполнять в ней программно. И не забыть о такой же доработке миникарточки.

Кстати, была такая идея от Вас же, только речь шла о правах, а не активностях.

И ещё похожая идея, только для определения записей, заведенных по OData.

Зверев Александр,

Да, в некоторых проектах делали заполнение названием процесса, но в стандартном элементе "Выполнить задачу" так просто поля не добавить. 
А ещё есть задачи, созданные при элементах "Открыть страницу редактирования", созданные в DCM...

Думал, вдруг есть что-то встроенное уже

Есть стандартный элемент БП «Привязать процесс к объекту», можно брать после создания брать Id задачи и вызывать его.

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

Здравствуйте. Столкнулся с проблемой следующего рода:
Появилась необходимость добавить действие на страницу редактирования активности.
Выполнил все пункты согласно инструкции на https://academy.terrasoft.ru/documents/technic-sdk/7-7/dobavlenie-deystviya-na-stranicu-redaktirovaniya . 
В результате получилась вот такая замещающая страница:

define("ActivityPageV2", ["ProcessModuleUtilities", "AbrConstants"],
    function(ProcessModuleUtilities, AbrConstants) {
        return {
            // Название схемы объекта страницы редактирования.
         entitySchemaName: "Activity",
         methods: {
          // Проверяет, в каком состоянии активность.
          isRunningMail: function() {
                if (this.get("Status") && this.get("Result")) {
                 return (this.get("Status").value === AbrConstants.Activity.State.Completed && this.get("Result").value === "632afdd2-f616-4ea6-87d2-8ed38eed8aff");
                }
                return false;
               },
            // Метод-обработчик действия.
          showActionInfo: function() {
                var args = {
                  sysProcessName: "SendEmailAboutTheApproval",
                  scope: this
                 };
                ProcessModuleUtilities.executeProcess(args);
                this.showInformationDialog("Оповещения в ДТ и ОД отправлены.");
               },
            // Переопределение базового виртуального метода, возвращающего коллекцию действий страницы редактирования.
          getActions: function() {
                // Вызывается родительская реализация метода для получения
                // коллекции проинициализированных действий базовой страницы.
                var actionMenuItems = this.callParent(arguments);
                // Добавление линии-разделителя.
                actionMenuItems.addItem(this.getButtonMenuItem({
                 Type: "Terrasoft.MenuSeparator",
                 Caption: ""
                }));
                // Добавление пункта меню в список действий страницы редактирования.
                actionMenuItems.addItem(this.getButtonMenuItem({
                    // Привязка заголовка пункта меню к локализуемой строке схемы.
                 "Caption": {bindTo: "Resources.Strings.SendEmailToOdAndDt"},
                    // Привязка метода-обработчика действия.
                 "Tag": "showActionInfo",
                    // Привязка свойства доступности пункта меню к значению, которое возвращает метод isRunning().
                 "Enabled": {bindTo: "isRunningMail"}
                }));
                return actionMenuItems;
               }
         }
        };
       }
);

Кнопка добавилась, но свойство "Enabled" работает некорректно.
Т.е. кнопка должна быть активна, когда задача имеет состояние "Завершена" и результат "Выполнена".
Но, когда мы со страницы активностей открываем задачу, которая имеет состояние "Завершена" и результат "Выполнена", кнопка всегда неактивна и никак не реагирует на изменения состояния или результата.

Но если просто обновить страницу, кнопка становится активна.

В чем может быть причина?

Нравится

14 комментариев
Лучший ответ

stique,

//PageV2
attributes: {
//На пейдже первым делом объявляю атрибут
//на который я буду биндить (байндить) свойство "enabled" кнопки
 "isOrderButtonEnabled": {
  "value": false
 }
},
messages: {
//Объявляю сообщение с направлением PUBLISH, которое будем отправлять на секцию
 "GetOrderButtonStatus": {
  mode: Terrasoft.MessageMode.PTP,
  direction: Terrasoft.MessageDirectionType.PUBLISH
 }
},
methods: {
//Объявляю метод, который буду запускать два раза
//При инициализации страницы и после сохранения
//Он проставляет атрибут для кнопки 
//и одновременно отправляет сообщение с текущим статусом на секцию
//Хотя здесь можно сделать лучше и отправлять не статус, а непосредственно значение true/false
 getOrderButtonStatus: function() {
  this.sandbox.publish("GetOrderButtonStatus", this.get("UsrStatus"), [this.sandbox.id]);
  var status = this.$UsrStatus;
  if (status && status.value === "caae507b-ccea-4275-967e-bb4f4c73a880") {
   this.set("isOrderButtonEnabled", true);
  }
  else {
   this.set("isOrderButtonEnabled", false);
  }
 },
 onEntityInitialized: function() {
  this.callParent(arguments);
//вызываем первый раз
  this.getOrderButtonStatus();
 },
 onSaved: function() {
  this.callParent(arguments);
//вызываем второй раз
  this.getOrderButtonStatus();
 }
},
diff: [
//У меня была обычная кнопка на карточке, у Вас в меню Действия
//Так что Вам нужно забиндить кнопку на атрибут в Вашем методе getActions()
 {
  "operation": "insert",
  "name": "creatingOrderButton",
  "values": {
   "itemType": 5,
   "caption": "Create order",
   "click": {
    "bindTo": "syncCreatingOrder"
   },
   "style": "green",
   "enabled": {
    "bindTo": "isOrderButtonEnabled"//забиндить на атрибут
   },
   "classes": {
    "textClass": "actions-button-margin-right"
   }
  },
  "parentName": "LeftContainer",
  "propertyName": "items",
  "index": 7
 }
]
 
 
 
 
 
//SectionV2
attributes: {
//Здесь объявляем такой же атрибут
 "isOrderButtonEnabled": {
  "value": false
 }
},
messages: {
//Объявляем такое же сообщение с направлением SUBSCRIBE
 "GetOrderButtonStatus": {
  mode: Terrasoft.MessageMode.PTP,
  direction: Terrasoft.MessageDirectionType.SUBSCRIBE
 }
},
methods: {
//в init подписываемся на нужное нам сообщение
//и если оно к нам приходит - запускается метод getOrderStatusButton
//Опять таки, здесь можно и нужно логику переделать, чтобы получать сразу значение true/false
//вместо статуса
 init: function() {
  this.callParent(arguments);
  this.sandbox.subscribe("GetOrderButtonStatus", function(value) { this.getOrderButtonStatus(value); }, this, [this.getCardModuleSandboxId()]);
 },
 getOrderButtonStatus: function(status) {
  if (status && status.value === "caae507b-ccea-4275-967e-bb4f4c73a880") {
   this.set("isOrderButtonEnabled", true);
  }
  else {
   this.set("isOrderButtonEnabled", false);
  }
 }
}

 

Насколько я понимаю и помню, то добавив действие на ActivityPageV2, это действие по-моему создается автоматически и в секции, средствами сообщений, я давно это тестил, уже не помню. В общем, в первом случае у вас кнопка ДЕЙСТВИЯ находится на ActivitySectionV2, а во втором случае кнопка ДЕЙСТВИЯ находится на ActivityPageV2, это две разные кнопки. И на пейдже у вас есть метод isRunningMail(), но на секции его нет. Вам нужно организовать передачу сообщения с пейджи на секцию какой там статус и результат, потому что на секции этой информации нет. У Вас случайно ошибки в консоль не сыпятся, когда вы открываете первый раз активность в совмещенном режиме? Я надеюсь, что хоть немного понятно изъяснился)) I'm doing my best)

Добавить комментарий

Alex Zaslavsky,

Нет, ошибок в консоли нет.

Может быть я путаю, но кажется, когда мы открываем задачу, ActivityPage сразу подгружается.

stique,

Если открыть задачу, которая поставлена по процессу, которая не завершена, то да, она сразу откроется в пейдже, а остальные задачи, при первом открытии, открываются в совмещенном режиме, насколько я понимаю.

Вот попробуйте в секцию добавить метод isRunningMail() который всегда возвращает true, для примера, и кнопка у вас, скорее всего, заработает.

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

Добавить комментарий

Alex Zaslavsky,

Кажется Вы правы! Как правильно поступить в таком случае?

Alex Zaslavsky пишет: Но, чтобы она отрабатывала так же, как на пейдже, нужно воспользоваться механизмом сообщений.

А где про этот механизм можно почитать? 

stique,

С механизмом сообщений знакомы? Sandbox

Я биндил свойство enabled на атрибут, на пейдже в методах onEntityInitialized и onSaved я отправлял сообщения на секшн и в зависимости от условий проставлял такой же атрибут в true или false.

Если нужно прям подробно, то могу позже описать полностью как я сделал.

Alex Zaslavsky,

Alex Zaslavsky пишет:
С механизмом сообщений знакомы? Sandbox

Увы нет, только неделю  как изучаю bpm)

Alex Zaslavsky пишет:
Если нужно прям подробно, то могу позже описать полностью как я сделал.

 Если Вас не затруднит, буду признателен. А пока постараюсь самостоятельно поковырять.

stique,

//PageV2
attributes: {
//На пейдже первым делом объявляю атрибут
//на который я буду биндить (байндить) свойство "enabled" кнопки
 "isOrderButtonEnabled": {
  "value": false
 }
},
messages: {
//Объявляю сообщение с направлением PUBLISH, которое будем отправлять на секцию
 "GetOrderButtonStatus": {
  mode: Terrasoft.MessageMode.PTP,
  direction: Terrasoft.MessageDirectionType.PUBLISH
 }
},
methods: {
//Объявляю метод, который буду запускать два раза
//При инициализации страницы и после сохранения
//Он проставляет атрибут для кнопки 
//и одновременно отправляет сообщение с текущим статусом на секцию
//Хотя здесь можно сделать лучше и отправлять не статус, а непосредственно значение true/false
 getOrderButtonStatus: function() {
  this.sandbox.publish("GetOrderButtonStatus", this.get("UsrStatus"), [this.sandbox.id]);
  var status = this.$UsrStatus;
  if (status && status.value === "caae507b-ccea-4275-967e-bb4f4c73a880") {
   this.set("isOrderButtonEnabled", true);
  }
  else {
   this.set("isOrderButtonEnabled", false);
  }
 },
 onEntityInitialized: function() {
  this.callParent(arguments);
//вызываем первый раз
  this.getOrderButtonStatus();
 },
 onSaved: function() {
  this.callParent(arguments);
//вызываем второй раз
  this.getOrderButtonStatus();
 }
},
diff: [
//У меня была обычная кнопка на карточке, у Вас в меню Действия
//Так что Вам нужно забиндить кнопку на атрибут в Вашем методе getActions()
 {
  "operation": "insert",
  "name": "creatingOrderButton",
  "values": {
   "itemType": 5,
   "caption": "Create order",
   "click": {
    "bindTo": "syncCreatingOrder"
   },
   "style": "green",
   "enabled": {
    "bindTo": "isOrderButtonEnabled"//забиндить на атрибут
   },
   "classes": {
    "textClass": "actions-button-margin-right"
   }
  },
  "parentName": "LeftContainer",
  "propertyName": "items",
  "index": 7
 }
]
 
 
 
 
 
//SectionV2
attributes: {
//Здесь объявляем такой же атрибут
 "isOrderButtonEnabled": {
  "value": false
 }
},
messages: {
//Объявляем такое же сообщение с направлением SUBSCRIBE
 "GetOrderButtonStatus": {
  mode: Terrasoft.MessageMode.PTP,
  direction: Terrasoft.MessageDirectionType.SUBSCRIBE
 }
},
methods: {
//в init подписываемся на нужное нам сообщение
//и если оно к нам приходит - запускается метод getOrderStatusButton
//Опять таки, здесь можно и нужно логику переделать, чтобы получать сразу значение true/false
//вместо статуса
 init: function() {
  this.callParent(arguments);
  this.sandbox.subscribe("GetOrderButtonStatus", function(value) { this.getOrderButtonStatus(value); }, this, [this.getCardModuleSandboxId()]);
 },
 getOrderButtonStatus: function(status) {
  if (status && status.value === "caae507b-ccea-4275-967e-bb4f4c73a880") {
   this.set("isOrderButtonEnabled", true);
  }
  else {
   this.set("isOrderButtonEnabled", false);
  }
 }
}

 

Alex Zaslavsky,

Ого, большое спасибо Вам за такой развернутый ответ.
Еще нашел информацию что можно использовать "reloadAll: true", но пока не знаю как это прикрутить)

 

stique,

Отпишитесь потом, получилось или нет :)

Alex Zaslavsky,

Сделал как Вы написали, все заработало, но чтобы свойство "Enabled" изменилось, нужно обязательно нажимать кнопку сохранить. Т.е. при изменении состояния без сохранения активности, доступность кнопки не меняется.

stique,

Ну я делал именно такую логику, чтобы юзер не мог просто сменить статус (временно, без сохранения) и жмакать кнопку, когда ему захочется))
Если Вам нужно другое поведение, то можно создать на пейдже атрибут, который будет реагировать на изменение полей "Результат" и "Статус" и отправлять сендбоксом сообщение в любой момент, при изменении этих полей. Но как по мне, это не совсем правильно. Но решать Вам)

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

Реализовал разделение календаря по сотрудникам в фильтре через кучу diff. Встал вопрос - как наполнить каждый разными данными?
По умолчанию activityCollection планировщика указан как ScheduleGridData. Соответственно, на каждый календарь на странице создаю ScheduleGridData0, ScheduleGridData1, ScheduleGridData2 и так далее и подставляю эти значения в каждый activityCollection, но календари становятся вообще пустыми. Я так понимаю, вопрос в методах отрисовки, но тогда придется переписывать половину CRM.
Подскажите, как каждый календарик наполнить своим содержимым или что нужно изменить?

Вот пример одного из календарей

{
            "operation": "insert",
            "name": "Schedule0",
            "parentName": "DataViewsContainer",
            "propertyName": "items",
            "values": {
                 "id": "ActivitySectionV2Scheduler0",
                 "selectors": {"wrapEl": "#ActivitySectionV2Scheduler0"},
                 "itemType": Terrasoft.ViewItemType.SCHEDULE_EDIT,
                 "visible": {"bindTo": "isSchedulerVisible0"},
                 "startHour": Terrasoft.SysSettings.cachedSettings.SchedulerTimingStart,
                 "displayStartHour": Terrasoft.SysSettings.cachedSettings.SchedulerDisplayTimingStart + "-00",
                 "dueHour": Terrasoft.SysSettings.cachedSettings.SchedulerTimingEnd,
                 "timeScale": {"bindTo": "getTimeScale"},
                 "period": {"bindTo": "getSchedulerPeriod"},
                 "timezone": [{}],
                 "startDate": null,
                 "dueDate": null,
	         "activityCollection": {"bindTo": "ScheduleGridData0"},
                 "selectedItems": {"bindTo": "SelectedRows"},
                 "changeSelectedItems": {"bindTo": "onChangeSelectedItems"},
                 "scheduleItemDoubleClick": {"bindTo": "onScheduleItemDoubleClick"},
                 "scheduleItemTitleMouseOver": {"bindTo": "scheduleItemTitleMouseOver"},
                 "scheduleItemTitleClick": {"bindTo": "scheduleItemTitleClick"},
                 "change": {"bindTo": "changeScheduleItem"},
                 "selection": {"bindTo": "SchedulerSelection"},
                 "floatingItemsCollection": {"bindTo": "SchedulerFloatItemsCollection"},
                 "selectionKeyPress": {bindTo: "onSelectionKeyPress"},
                 "floatingItemReady": {"bindTo": "onFloatingItemReady"},
                 "selectionKeyPressSymbols": {"bindTo": "SchedulerSelectionPressedKeys"},
                 "itemBindingConfig": {
                     "itemId": {"bindTo": "Id"},
                     "title": {"bindTo": "getScheduleItemTitle"},
                     "changeTitle": {"bindTo": "onTitleChanged"},
                     "startDate": {"bindTo": "StartDate"},
                     "changeStartDate": {"bindTo": "onStartDateChanged"},
                     "dueDate": {"bindTo": "DueDate"},
                     "changeDueDate": {"bindTo": "onDueDateChanged"},
                     "status": {"bindTo": "getScheduleItemStatus"},
                     "changeStatus": {"bindTo": "onStatusChanged"},
                     "background": {"bindTo": "Background"},
                     "fontColor": {"bindTo": "FontColor"},
                     "isBold": {"bindTo": "IsBold"},
                     "isItalic": {"bindTo": "IsItalic"},
                     "isUnderline": {"bindTo": "IsUnderline"},
                     "markerValue": {"bindTo": "getScheduleItemHint"}
                   },
                   "floatingItemBindingConfig": {
                        "caption": {"bindTo": "getSimpleModuleCaption"},
                        "width": {"bindTo": "getSimpleModuleWidth"}
                   }
}

 

Нравится

1 комментарий

Смотрите, как реализовано расписание для нескольких пользователей в дополнении «Advanced schedule for bpm'online». 

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

Добрый день. 

Не все оповещения уходят пользователям, активность тип email, остаются в черновиках в состоянии "Не отправлено", приходится отправлять вручную. Как установить причину ? Или как отправить "разом" все оповещения за день, нету возможности выбора всех писем. Сама почта работает стабильно, проверяли. Прошу помочь.

Прикрепленные файлы

Нравится

1 комментарий
Лучший ответ

Начните с просмотра логов вашего почтового сервера (при необходимости включите логирование, привлеките к решению проблемы администратора почтовой системы)  почему письма сразу не отправляются. 

Как происходит отправка уведомлений и проблема касается только уведомлений или и других почтовsых сообщений? Скорее всего есть БПР который отправляет уведомления, проверьте какой тип отправки указан в нем, ручная отправка или автоматическая?

Начните с просмотра логов вашего почтового сервера (при необходимости включите логирование, привлеките к решению проблемы администратора почтовой системы)  почему письма сразу не отправляются. 

Как происходит отправка уведомлений и проблема касается только уведомлений или и других почтовsых сообщений? Скорее всего есть БПР который отправляет уведомления, проверьте какой тип отправки указан в нем, ручная отправка или автоматическая?

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