Добрый день

У меня есть в карточке Активности поле Трудозатраты (тип - целое число) и в карточке Индидента поле Итоговые Трудозатраты (тип - целое число).
Подскажите, пожалуйста, как сделать так, чтобы Трудозатраты в Инциденте показывали сумму трудозатрат из всех Активностей с типом Задача, привязанных к данному Инциденту. Заранее спасибо.

Нравится

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

Пользовательскими средствами такое сделать нельзя.
Нужно либо сделать отдельный бизнес-процесс, проводящий необходимые вычисления, либо логику на объекте «Активность» на события добавления, удаления активности или её сохранения с новым значением поля. Ещё один вариант реализации — триггер на таблицу Activity, делающий то же самое на уровне БД (см. пример).

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

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

карточка

Нравится

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

Здравствуйте.
У меня есть страница для ввода параметров поиска. Страница не привязана ни к какому объекту. Значения из её полей передаются в параметры бизнес-процесса, выполняющего поиск. Как мне с помощью функции asyncValidate из BasePageV2 проверить, что на моей странице поиска заполнены все поля?

Нравится

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

Здравствуйте, Евгений!

Для поля Вы можете использовать свойство enable: true. Этот признак сделает поле обязательным для заполнения. Таким образом Вы сможете осуществить валидацию на заполнения полей значениями.

Алексей, у меня в ТЗ указано, в частности, условие, что заполнение любого из полей не обязательно. Поэтому, я и прошу показать мне как проверить заполнение полей с помощью asyncValidate. Моя страница унаследована от модуля "Базовая схема карточки" из пакета NUI. К этому посту я прикрепил текстовый файл, содержащий Javascript страницы.

Евгений, добрый день!

Рекомендую Вам посмотреть реализацию данного метода в DocumentPageV2. Вы можете реализовать необходимый функционал по аналогии. Сначала необходимо реализовать метод проверки заполненности полей (по аналогии с validateAccountOrContactFilling), который принимает в качестве входящих параметров функцию обратного вызова и контекст выполнения, потом вызвать его в asyncValidate. Например:

asyncValidate: function(callback, scope) {
	this.callParent([function(response) {
		if (!this.validateResponse(response)) {
			return;
		}
		Terrasoft.chain(
			function(next) {
				this.myValidationMethod(function(response) {
					if (this.validateResponse(response)) {
						next();
					}
				}, this);
			},
			function() {
				callback.call(scope, response);
			},
			this);
		}, this]);
},

Спасибо.

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

Займався створенням нового розділу за принципом розділу "Пользователи" (того, що в робочих місцях не відображено).
Потрібно було в процесі відладки подивитись, як веде себе "Страница реестра вхождения в роли" (AdministrativeUserInRoleGridPage).
В дизайнері схеми був присутній пул з доріжкою й субпроцесом, в якому шаблонами були внесені "Начальное сообщение" зв"язане з "Промежуточным генерирующим сообщением", причому обидва не проініціалізовані. При збереженні схеми в такій ситуації видається помилка на обидва елементи.
Як на мене, весь цей пул з доріжкою, субпроцесом і пустипи елементами був зайвий і я його зтер.
Схему опублікував.
Після цього, при спробі відкрити розділ "Администрирование.Пользователи" отримую помилку в
AdministrationUnitsGridPageEventsProcess.ScriptChildDataSourceLoadRowsResponseRegisteredExecute
в коді:

var buttonMenu = Page.AddButton.Menu;
var organizationMenuItem = buttonMenu.Find(item => item.Name.Contains(new Guid("DF93DCB9-6BD7-DF11-9B2A-001D60E938C6").ToString("N")));
var unitMenuItem = buttonMenu.Find(item => item.Name.Contains(new Guid("B659F1C0-6BD7-DF11-9B2A-001D60E938C6").ToString("N")));
var chiefMenuItem = buttonMenu.Find(item => item.Name.Contains(new Guid("B759F1C0-6BD7-DF11-9B2A-001D60E938C6").ToString("N")));
var teamMenuItem = buttonMenu.Find(item => item.Name.Contains(new Guid("462E97C7-6BD7-DF11-9B2A-001D60E938C6").ToString("N")));

Власне помилку генерує наступний код:
organizationMenuItem.Enabled = true;
unitMenuItem.Enabled = true;
chiefMenuItem.Enabled = !hasUnitChief;
teamMenuItem.Enabled = true;

По тій причині, що всі означені об'єкти = NULL.

(Зауважу, що дану схему я не чіпав)

Я не схильний новоотриману помилку пов'язувати із знищенням того самого пулу з доріжкою (хоча й не буду це категорично заперечувати).

Я ще попередньо спочатку створив вже існуючий розділ "Администрирование", потім вилучив його, далі виявив, що він і в таблиці [SysModule] зник, тому запис імпортував з оригінальної БД.
Потім я так само створив вже існуючий розділ "Пользователи", який відобразився зо всім пакетом деталей.
Вже після цього я вилучав порожні елементи й публікував схему.

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

Нравится

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

Якщо потрібен скан помилки - можу відправити в приват

Посмотрел на коробке эту страницу, там только 3 подпроцесса по сообщениям: «OpenRoles», «DeleteButtonClick» и «PageLoad».

процесс

Возможно, Вы смотрите на версию страницы с чьими-то доработками.

Шукаю зараз, де формується меню для кнопки "Добавить" для розділу "Администрирование.Элементы организационной структуры"
(те, що читається в AdministrationUnitsGridPageEventsProcess.ScriptChildDataSourceLoadRowsResponseRegisteredExecute)

Игорь, это стандартный механизм для раздела с несколькими карточками для разных типов. В BaseGridPage в скрипте ScriptTaskBaseGridPageInit:

var editPages = GetEditPages();
if (TypeColumnUId != Guid.Empty && Page.DataSource.CurrentStructure.Columns.FindByMetaPath(TypeColumnUId.ToString()) == null) {
	var typeColumn = Page.DataSource.Schema.Columns.GetByUId(TypeColumnUId);
	var column = Page.DataSource.CurrentStructure.AddColumnByPath(typeColumn.Name);
	column.IsVisible = false;
	column.IsAlwaysSelect = true;
}
foreach (var item in editPages) {
	var addMenuItem = CreateAddButtonMenuItem(item.Value, item.Key);
	Page.AddButton.Menu.Add(addMenuItem);
	if (!IsContextHelpButtonInitialized) {
		string formatString = "{0}.on('click', function(el) {{ {1} }}, this)";
		var parameters =  item.Key.Split('&');
		var typeEditPageUId = new Guid(parameters[0]);
		var typeEntityId = new Guid(parameters[1]);
		var typeEditPageUIds = TypeEditPageUIds as Dictionary<Guid, Dictionary<string, Guid>>;
		string script = GetRegisterAddPageScript(typeEditPageUId, typeEditPageUIds[typeEntityId]["SysModuleEditId"], typeEntityId);
		Page.AddScript(string.Format(formatString, addMenuItem.ClientID, script));		
	}
}

Я вже теж дійшов висновку, що щось не так з типами карточок.
Перевірив запис розділу [Пользователи], - виявилось, що в результаті маніпуляцій з розділами (в робочих місцях) збилися параметри
[Использовать отдельные карточки для работы с записями разного типа]
[Тип записи указан в колонке]

При спробі відновити значення через стандартну форму виходило повідомлення:

Необходимые элементы конфигурации не найдены
Для использования групп необходимы следующие объекты: AdministrativeUsersFolder, AdministrativeUsersInFolder

Подивився на робочій - відсутні такі об'єкти, тому відновив значення через SQL - все запрацювало.
Дякую за підказку :smile:.

Цікаво, а як формувався запис розділу [Пользователи], зважаючи на те, що в оригінальній версії він відсутній у списку робочих місць, і навіть якщо його добавити, то для збереження все одно ще треба створювати два додаткових об'єкти
[AdministrativeUsersFolder] та [AdministrativeUsersInFolder]
які, як видно, насправді не були створені і тим не менше, розділ чудово функціонує без вказаних об'єктів.

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

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

Есть ли возможность организовать автоматический обзвон по контактам, какие модули/интеграции требуются, кроме IP-телефонии?

Нравится

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

Автоматический обзвон контактов выполняется исключительно самой АТС, bpm'online не принимает в нем участия. Дополнительно, для удобства администратора контакт-центра может быть настроено получение списка контактов на обзвон.

Для реализации задачи требуется дополнительная доработка интеграции:
Создание раздела в bpm'online позволяющего формировать список на обзвон
Формирование службы передающей номер телефона и ID записи для обзвона (Web-сервисы, шлюзовая таблица и т.д.)
Организация обратной связи с результатами обзвона
Реализация зависит от типа АТС, ее возможностей к интеграции и выбранных специалистами способов реализации.

Альтернативой может быть использование CustomerService (https://terrasoft.ru/service/customer-service/360-customer-view)
Плюсом является использование автоматических выборок на основе динамической очереди и возможность запуска бизнес-процессов по звонкам в разных исходящих кампаниях.

Добрый день!

А если переформулировать так: "Как создать (генерировать) очередь Активностей (Звонок) для группы Контактов?"
1. Для одноразового создания Задач для "статического списка" Контактов.
2. Если группа динамическая то, чтобы Оператор каждое утро в разделе "Единое окно" видел перечень новых Задач (по обзвону Клиентов, которые теперь также удовлетворяют условиям группы).
---
Пункт 2 скорее всего стандартными средствами bpmonline не решается, но первый-то должен, нет?

Спасибо.

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

Создать статический список контактов Вы можете, отметив их тегом. Подробнее о тегах Вы можете прочитать по ссылке:
https://academy.terrasoft.ru/documents/sales-commerce/7-8-0/gruppy-i-te…

Далее, Вы можете создать динамическую группу в разделе "Контакты" с фильтром:
Тег в записи раздела контакты (по колонке Объект) существует
и Тег = <выберите созданный Вами тег>

Далее создайте очередь на основании созданной Вами группы.

Также, как вариант, вместо создания динамической группы и очереди, Вы можете создать бизнес процесс:
1) Стартовый элемент
2) Добавить данные в объект "Активность" в режиме выборки из объекта "Тег в записи раздела контакты".
Условия фильтрации выборки Тег = <выберите созданный Вами тег>
Вам необходимо заполнить поля "Заголовок" (произвольный), тип "Выполнить", категория "Звонок", контакт - из выборки Id.
3) Конец процесса

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

Добрый день ! Подскажите пожалуйста как создать очередь на основании созданной группы?

Оксана, добрый день!

Очередь можно наполнить фильтром, рекомендованным Алексеем для статической группы -
Тег в записи раздела контакты (по колонке Объект) существует
и Тег = <выберите созданный Вами тег>

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

Заранее спасибо за ответ!

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

Заранее спасибо за ответ!

Добрый день, Оксана!

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

Добрый день, Илья! Ранее Алексей отвечал, что обзвон можно осуществить в рамках бизнес-процесса. могу ли я уточнить у Вас некоторые моменты? Насколько я понимаю, мы создаем бизнес процесс, и в него добавляем один элемент "Выполнить задачу". Далее в параметре категория указываем "звонок". А дальше непонятно в каком из параметров делается выборка.
Буду благодарна за быстрый ответ

Добрый день.
С позиции пользователя:

  • Выбрал нужные контакты
  • Выбрал действия, создать очередь обзвона(возможно ли добавить новое действие в "действия")
  • После выполнения этих действий АТС должна начинать обзвон

С позиции разработчика:

  • Выбрал нужные контакты, сохранил их UUID
  • Создал задачи для контакта, сохранил их UUID
  • Запустил перебор по сохраненному списку

Из явных минусов:

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

Это логика, которую мы будем закладывать в интеграцию.
На этой неделе будем тестировать.
Если в логике что то не правильно - прошу скорректировать.

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

Заранее спасибо!

"APanyovin" написал:

Добрый день.

С позиции пользователя:

  • Выбрал нужные контакты
  • Выбрал действия, создать очередь обзвона(возможно ли добавить новое действие в "действия")
  • После выполнения этих действий АТС должна начинать обзвон

С позиции разработчика:

  • Выбрал нужные контакты, сохранил их UUID
  • Создал задачи для контакта, сохранил их UUID
  • Запустил перебор по сохраненному списку

Из явных минусов:

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

Это логика, которую мы будем закладывать в интеграцию.

На этой неделе будем тестировать.

Если в логике что то не правильно - прошу скорректировать.

--

Runtel

Alexey Panyovin

Добрый день, Оксана.

Я постарался описать процесс.
Давайте начнем с главного - на чем пишем и какое api используете?

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

"APanyovin" написал:

Добрый день, Оксана.

Я постарался описать процесс.

Давайте начнем с главного - на чем пишем и какое api используете?

--

Runtel

Alexey Panyovin

Доброе утро, Оксана.
В создании БП наверное не помогу.
У нас создание списка и его контроть осуществляет АТС.

Доброе утро, Алексей!

А кто бы мне мог помочь в данном вопросе?

"APanyovin" написал:

Доброе утро, Оксана.

В создании БП наверное не помогу.

У нас создание списка и его контроть осуществляет АТС.

--

Runtel

Alexey Panyovin

Доброе утро, Алексей!

А кто бы мне мог помочь в данном вопросе?

"APanyovin" написал:

Доброе утро, Оксана.

В создании БП наверное не помогу.

У нас создание списка и его контроть осуществляет АТС.

--

Runtel

Alexey Panyovin

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

Вы можете обратиться к менеджеру, который найдет оптимальный вариант построения процесса. Альтернатива - использование продукта Customer Center.

В этом продукте есть раздел "Очереди", который позволяет выстраивать записи в очередь. Условия попадания в очередь настраиваются в фильтре очереди. Подробно можно прочитать по ссылке.

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

Доброго дня!
В стандартном типе(когда еще не создавал своих) на карточке Контакта был такой элемент: PhotoContainer.
При нового типа его вставить с мастера разделов нельзя.
Начальство очень хочет. Как можно его вставить?
Я еще новичок, поэтому буду очень рад если ответите подробно как сделать.

Нравится

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

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

Пример, как создать поле, в которое можно вставить фото:

Этот кусок кода необходимо вставлять в секцию diff в замещающий клиентский модуль схемы карточки или новый созданный модуль.

{

"operation": "insert",

"name": "PhotoContainer",

"values": {

"itemType": 7,

"wrapClass": [

"image-edit-container"

],

"layout": {

"column": 0,

"row": 0,

"rowSpan": 3,

"colSpan": 2

},

"items": []

},

"parentName": "Header",

"propertyName": "items",

"index": 7

},

{

"operation": "insert",

"name": "Photo",

"values": {

"getSrcMethod": "getSrcMethod",

"onPhotoChange": "onPhotoChange",

"beforeFileSelected": "beforeFileSelected",

"readonly": false,

"defaultImage": "http://PHOTO_PHOTO_PHOTO.PHOTO",

"generator": "ImageCustomGeneratorV2.generateCustomImageControl"

},

"parentName": "PhotoContainer",

"propertyName": "items",

"index": 0

}

methods: {

getSrcMethod: function() {

var primaryImageColumnValue = this.get(this.primaryImageColumnName);

if (primaryImageColumnValue) {

return this.getSchemaImageUrl(primaryImageColumnValue);

}

return this.Terrasoft.ImageUrlBuilder.getUrl(resources.localizableImages.DefaultPhoto);

},

onPhotoChange: function(photo) {

if (!photo) {

this.set(this.primaryImageColumnName, null);

return;

}

this.Terrasoft.ImageApi.upload({

file: photo,

onComplete: this.onPhotoUploaded,

onError: this.Terrasoft.emptyFn,

scope: this

});

},

onPhotoUploaded: function(imageId) {

var imageData = {

value: imageId,

displayValue: "Photo"

};

this.set(this.primaryImageColumnName, imageData);

},

У меня в конфигурации есть:
Схема страницы редактирования раздела "Контакты" с типом "Физическое лицо"

Это сюда вставлять?

пока удалил

Нашел статью: ВОТ
Где все описано. Столкнулся вот с чем:
У меня для Контакта есть 6 страниц(схем), они сгенерились когда я создавал типы.
Для одной из них(Схема страницы редактирования раздела "Контакты" с типом "Физическое лицо"), мне надо вывести фото.
Как я понял, надо создать замещающую схему страницы, так как при сохранении чего нить на оригинале вылазят ошибки JS на каждую строку. Но столкнулся вот с чем. По стандарту bpm создал схемы в пакете Custom, и создать в этом же пакете замещающую страницу я не могу(пишет нельзя создать в одном пакете). Я создал новый пакет, но не могу его унаследовать от Custom, а ведь там мои схемы.
Как мне поступить?

Плиз хэлп!

Виктиор, пакет Custom, как раз содержит в себе все замещающие схемы и объекты. Именно в них можно вносить корректировки.

"Липатов Юрий Сергеевич" написал:

Виктиор, пакет Custom, как раз содержит в себе все замещающие схемы и объекты. Именно в них можно вносить корректировки.


Тогда очень странно. При попытке сохранить схему, вываливаются js ошибки на все строки.
вот скрин: картинко
Кругами обвел вставленый код и ошибки.

Виктор, это предупреждения.
Вы проверили функциональность кода, он работает?

В данном случае я сделал чисто для примера.
Не знал что error это предупреждение)
И так я сделал все по мануалу.
При попытке загрузить новое фото ничего не происходит. Висит дальше дефолтовая картинка.
Прилаживаю скриншоты. И код.
1
2

define('UsrContactType3Page', ['UsrContactType3PageResources', 'GeneralDetails'],
function(resources, GeneralDetails) {
	return {
		entitySchemaName: 'Contact',
		details: /**SCHEMA_DETAILS*/{
	"PropertyCon": {
		"schemaName": "PropertyConDetail",
		"entitySchemaName": "PropertyCon",
		"filter": {
			"detailColumn": "Contact",
			"masterColumn": "Id"
		}
	}
}/**SCHEMA_DETAILS*/,
		diff: /**SCHEMA_DIFF*/[
	{
		"operation": "insert",
		"name": "Name",
		"values": {
			"layout": {
				"column": 0,
				"row": 0,
				"colSpan": 12,
				"rowSpan": 1
			}
		},
		"parentName": "Header",
		"propertyName": "items",
		"index": 0
	},
	{
		"operation": "insert",
		"name": "Type",
		"values": {
			"layout": {
				"column": 12,
				"row": 1,
				"colSpan": 12,
				"rowSpan": 1
			},
			"bindTo": "Type",
			"caption": {
				"bindTo": "Resources.Strings.TypeCaption"
			},
			"enabled": true
		},
		"parentName": "Header",
		"propertyName": "items",
		"index": 1
	},
	{
		"operation": "insert",
		"name": "Owner",
		"values": {
			"layout": {
				"column": 12,
				"row": 0,
				"colSpan": 12,
				"rowSpan": 1
			},
			"bindTo": "Owner",
			"caption": {
				"bindTo": "Resources.Strings.OwnerCaption"
			},
			"enabled": true
		},
		"parentName": "Header",
		"propertyName": "items",
		"index": 2
	},
	{
		"operation": "insert",
		"name": "Job",
		"values": {
			"layout": {
				"column": 0,
				"row": 1,
				"colSpan": 12,
				"rowSpan": 1
			},
			"bindTo": "Job",
			"caption": {
				"bindTo": "Resources.Strings.JobCaption"
			},
			"enabled": true
		},
		"parentName": "Header",
		"propertyName": "items",
		"index": 3
	},
	{
		"operation": "insert",
		"name": "UsrDepartment",
		"values": {
			"layout": {
				"column": 0,
				"row": 2,
				"colSpan": 12,
				"rowSpan": 1
			},
			"bindTo": "UsrDepartment",
			"caption": {
				"bindTo": "Resources.Strings.UsrDepartmentCaption"
			},
			"enabled": true
		},
		"parentName": "Header",
		"propertyName": "items",
		"index": 4
	},
	{
		"operation": "insert",
		"name": "UsrCustomerTypeField",
		"values": {
			"layout": {
				"column": 12,
				"row": 2,
				"colSpan": 12,
				"rowSpan": 1
			},
			"bindTo": "UsrCustomerTypeField",
			"caption": {
				"bindTo": "Resources.Strings.CustomerTypeFieldCaption"
			},
			"textSize": 0,
			"contentType": 3,
			"labelConfig": {
				"visible": true
			},
			"enabled": true
		},
		"parentName": "Header",
		"propertyName": "items",
		"index": 5
	},
	{
		"operation": "insert",
		"name": "UsrStatus",
		"values": {
			"layout": {
				"column": 12,
				"row": 3,
				"colSpan": 12,
				"rowSpan": 1
			},
			"bindTo": "UsrStatus",
			"caption": {
				"bindTo": "Resources.Strings.StatusCaption"
			},
			"textSize": 0,
			"contentType": 3,
			"labelConfig": {
				"visible": true
			},
			"enabled": true
		},
		"parentName": "Header",
		"propertyName": "items",
		"index": 6
	},
	{
		"operation": "insert",
		"name": "DescMain",
		"values": {
			"layout": {
				"column": 0,
				"row": 3,
				"colSpan": 12,
				"rowSpan": 1
			},
			"bindTo": "DescMain",
			"caption": {
				"bindTo": "Resources.Strings.DescMainCaption"
			},
			"textSize": 0,
			"contentType": 0,
			"labelConfig": {
				"visible": true
			},
			"enabled": true
		},
		"parentName": "Header",
		"propertyName": "items",
		"index": 7
	},
	{
		"operation": "insert",
		"name": "Account",
		"values": {
			"layout": {
				"column": 0,
				"row": 4,
				"colSpan": 12,
				"rowSpan": 1
			},
			"bindTo": "Account",
			"caption": {
				"bindTo": "Resources.Strings.AccountCaption"
			},
			"enabled": true
		},
		"parentName": "Header",
		"propertyName": "items",
		"index": 8
	},
	{
		"operation": "insert",
		"name": "PersonContactId",
		"values": {
			"layout": {
				"column": 12,
				"row": 4,
				"colSpan": 12,
				"rowSpan": 1
			},
			"bindTo": "PersonContactId",
			"caption": {
				"bindTo": "Resources.Strings.PersonContactIdCaption"
			},
			"textSize": 0,
			"contentType": 1,
			"labelConfig": {
				"visible": true
			},
			"enabled": true
		},
		"parentName": "Header",
		"propertyName": "items",
		"index": 9
	},
	{
		"operation": "insert",
		"name": "GeneralInfoTab",
		"values": {
			"caption": {
				"bindTo": "Resources.Strings.GeneralInfoTabCaption"
			},
			"items": []
		},
		"parentName": "Tabs",
		"propertyName": "tabs",
		"index": 0
	},
	{
		"operation": "insert",
		"name": "group",
		"values": {
			"itemType": 15,
			"caption": {
				"bindTo": "Resources.Strings.groupCaption"
			},
			"items": [],
			"controlConfig": {
				"collapsed": false
			}
		},
		"parentName": "GeneralInfoTab",
		"propertyName": "items",
		"index": 0
	},
	{
		"operation": "insert",
		"name": "group_gridLayout",
		"values": {
			"itemType": 0,
			"items": []
		},
		"parentName": "group",
		"propertyName": "items",
		"index": 0
	},
	{
		"operation": "insert",
		"name": "MobilePhone",
		"values": {
			"layout": {
				"column": 0,
				"row": 0,
				"colSpan": 12,
				"rowSpan": 1
			},
			"bindTo": "MobilePhone",
			"caption": {
				"bindTo": "Resources.Strings.MobilePhoneCaption"
			},
			"enabled": true
		},
		"parentName": "group_gridLayout",
		"propertyName": "items",
		"index": 0
	},
	{
		"operation": "insert",
		"name": "Email",
		"values": {
			"layout": {
				"column": 12,
				"row": 0,
				"colSpan": 12,
				"rowSpan": 1
			},
			"bindTo": "Email",
			"caption": {
				"bindTo": "Resources.Strings.EmailCaption"
			},
			"enabled": true
		},
		"parentName": "group_gridLayout",
		"propertyName": "items",
		"index": 1
	},
	{
		"operation": "insert",
		"name": "Phone",
		"values": {
			"layout": {
				"column": 0,
				"row": 1,
				"colSpan": 12,
				"rowSpan": 1
			},
			"bindTo": "Phone",
			"caption": {
				"bindTo": "Resources.Strings.PhoneCaption"
			},
			"enabled": true
		},
		"parentName": "group_gridLayout",
		"propertyName": "items",
		"index": 2
	},
	{
		"operation": "insert",
		"name": "UsrOtherEmail",
		"values": {
			"layout": {
				"column": 12,
				"row": 1,
				"colSpan": 12,
				"rowSpan": 1
			},
			"bindTo": "UsrOtherEmail",
			"caption": {
				"bindTo": "Resources.Strings.OtherEmailCaption"
			},
			"textSize": 0,
			"contentType": 1,
			"labelConfig": {
				"visible": true
			},
			"enabled": true
		},
		"parentName": "group_gridLayout",
		"propertyName": "items",
		"index": 3
	},
	{
		"operation": "insert",
		"name": "UsrHomePhone",
		"values": {
			"layout": {
				"column": 0,
				"row": 2,
				"colSpan": 12,
				"rowSpan": 1
			},
			"bindTo": "UsrHomePhone",
			"caption": {
				"bindTo": "Resources.Strings.HomePhoneCaption"
			},
			"textSize": 0,
			"contentType": 1,
			"labelConfig": {
				"visible": true
			},
			"enabled": true
		},
		"parentName": "group_gridLayout",
		"propertyName": "items",
		"index": 4
	},
	{
		"operation": "insert",
		"name": "BirthDate",
		"values": {
			"layout": {
				"column": 12,
				"row": 2,
				"colSpan": 12,
				"rowSpan": 1
			},
			"bindTo": "BirthDate",
			"caption": {
				"bindTo": "Resources.Strings.BirthDateCaption"
			},
			"enabled": true
		},
		"parentName": "group_gridLayout",
		"propertyName": "items",
		"index": 5
	},
	{
		"operation": "insert",
		"name": "UsrOtherPhone",
		"values": {
			"layout": {
				"column": 0,
				"row": 3,
				"colSpan": 12,
				"rowSpan": 1
			},
			"bindTo": "UsrOtherPhone",
			"caption": {
				"bindTo": "Resources.Strings.OtherPhoneCaption"
			},
			"textSize": 0,
			"contentType": 1,
			"labelConfig": {
				"visible": true
			},
			"enabled": true
		},
		"parentName": "group_gridLayout",
		"propertyName": "items",
		"index": 6
	},
	{
		"operation": "insert",
		"name": "DoNotUseEmail",
		"values": {
			"layout": {
				"column": 12,
				"row": 3,
				"colSpan": 6,
				"rowSpan": 1
			},
			"bindTo": "DoNotUseEmail",
			"caption": {
				"bindTo": "Resources.Strings.DoNotUseEmailCaption"
			},
			"enabled": true
		},
		"parentName": "group_gridLayout",
		"propertyName": "items",
		"index": 7
	},
	{
		"operation": "insert",
		"name": "DoNotUseCall",
		"values": {
			"layout": {
				"column": 18,
				"row": 3,
				"colSpan": 6,
				"rowSpan": 1
			},
			"bindTo": "DoNotUseCall",
			"caption": {
				"bindTo": "Resources.Strings.DoNotUseCallCaption"
			},
			"enabled": true
		},
		"parentName": "group_gridLayout",
		"propertyName": "items",
		"index": 8
	},
	{
		"operation": "insert",
		"name": "UsrRegAdress",
		"values": {
			"layout": {
				"column": 0,
				"row": 4,
				"colSpan": 24,
				"rowSpan": 1
			},
			"bindTo": "UsrRegAdress",
			"caption": {
				"bindTo": "Resources.Strings.RegAdressCaption"
			},
			"textSize": 0,
			"contentType": 1,
			"labelConfig": {
				"visible": true
			},
			"enabled": true
		},
		"parentName": "group_gridLayout",
		"propertyName": "items",
		"index": 9
	},
	{
		"operation": "insert",
		"name": "Address",
		"values": {
			"layout": {
				"column": 0,
				"row": 5,
				"colSpan": 24,
				"rowSpan": 1
			},
			"bindTo": "Address",
			"caption": {
				"bindTo": "Resources.Strings.AddressCaption"
			},
			"enabled": true
		},
		"parentName": "group_gridLayout",
		"propertyName": "items",
		"index": 10
	},
	{
		"operation": "insert",
		"name": "UsrCurrentLoans",
		"values": {
			"layout": {
				"column": 0,
				"row": 6,
				"colSpan": 24,
				"rowSpan": 1
			},
			"bindTo": "UsrCurrentLoans",
			"caption": {
				"bindTo": "Resources.Strings.CurrentLoansCaption"
			},
			"textSize": 0,
			"contentType": 0,
			"labelConfig": {
				"visible": true
			},
			"enabled": true
		},
		"parentName": "group_gridLayout",
		"propertyName": "items",
		"index": 11
	},
	{
		"operation": "insert",
		"name": "PropertyCon",
		"values": {
			"itemType": 2
		},
		"parentName": "GeneralInfoTab",
		"propertyName": "items",
		"index": 1
	},
                // Контейнер-обертка, в который будет размещен логотип контрагента.
                {
                    "operation": "insert",
                    "parentName": "Header",
                    "propertyName": "items",
                    "name": "PhotoContainer",
                    "values": {
                        // Тип элемента - контейнер.
                        "itemType": Terrasoft.ViewItemType.CONTAINER,
                        "wrapClass": ["image-edit-container"],
                        "layout": { "column": 0, "row": 0, "rowSpan": 4, "colSpan": 4 },
                        "items": []
                    }
                },
                // Поле [Picture] — поле с логотипом контрагента.
                {
                    "operation": "insert",
                    "parentName": "PhotoContainer",
                    "propertyName": "items",
                    "name": "Picture",
                    "values": {
                        // Наименование метода, который получает изображение по ссылке.
                        "getSrcMethod": "getAccountImage",
                        // Наименование метода, который вызывается при изменении изображения.
                        "onPhotoChange": "onPhotoChange",
                        // Свойство, которое определяет возможность редактирования (изменения, удаления) изображения.
                        "readonly": false,
                        // Изображение, которое будет отображаться по умолчанию.
                        "defaultImage": Terrasoft.ImageUrlBuilder.getUrl(resources.localizableImages.DefaultPhoto),
                        // Генератор элемента управления.
                        "generator": "ImageCustomGeneratorV2.generateCustomImageControl"
                    }
                }
]/**SCHEMA_DIFF*/,
		attributes: {},
		methods: {
                // Возвращает url логотипа контрагента по ссылке, сохраненной в объекте.
                getAccountImage: function () {
                    // Получаем ссылку на изображение из колонки объекта.
                    var imageColumnValue = this.get("PhotoClient");
                    // Если ссылка установлена, то возвращает url файла с изображением.
                    // Если нет, то вызывает метод, возвращающий изображение по умолчанию.
                    if (imageColumnValue) {
                        return this.getSchemaImageUrl(imageColumnValue);
                    }
                    return this.getAccountDefaultImage();
                },
                // Возвращает url логотипа контрагента по умолчанию.
                getAccountDefaultImage: function () {
                    return this.Terrasoft.ImageUrlBuilder.getUrl(this.get("Resources.Images.DefaultPhoto"));
                },
                // Обрабатывает изменение логотипа контрагента. В качестве параметра принимает файл с изображением.
                onPhotoChange: function (photo) {
                    if (!photo) {
                        this.set("PhotoClient", null);
                        return;
                    }
                    // Выполняется загрузка файла в базу данных. По окончании загрузки вызывается метод, который
                    // сохраняет ссылку на измененное изображение в колонке [Логотип] объекта [Контрагент].
                    this.Terrasoft.ImageApi.upload({
                        file: photo,
                        onComplete: this.onPhotoUploaded,
                        onError: this.Terrasoft.emptyFn,
                        scope: this
                    });
                },
                // Метод, который сохраняет ссылку на измененное изображение. В качестве параметра передается Id 
                // сохраненного файла из базы данных.
                onPhotoUploaded: function (imageId) {
                    var imageData = {
                        value: imageId,
                        displayValue: "Image"
                    };
                    // Полю с изображением присваивается ссылка на изображение.
                    this.set("PhotoClient", imageData);
                }
 
		},
		rules: {},
		userCode: {}
	};
});

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

Например, убедитесь, что в колонке «Изображение» объекта «Контакт» выбрана пользовательская колонка (например, "PhotoClient"), а не базовая. Должно помочь. См. пикчу

Спасибо!

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

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

Подскажите как в замещающей схеме удалить бизнес правила на примере раздела активности.
Есть две предустановленные схемы Document.ActivityPageV2 и DocumentInOpportunity.ActivityPageV2 (замещают UIv2.ActivityPageV2) в них содержаться бизнес правила фильтрации по контрагенту, контакту и продаже.
Эти правила нужно убрать, вернее оставить только фильтрацию по контрагенту. Пока мои попытки ничего не дали, пробовал в своей замещающей схеме добавить бизнес правило с существующем названием и другим фильтром, но оно просто добавилось к остальным.

Нравится

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

Попробуйте заместить бизнес-правило, которое хотите отключить и проставить свойство enabled: false.

"Мотков Илья" написал:

Попробуйте заместить бизнес-правило, которое хотите отключить и проставить свойство enabled: false.

Нет не помогло.
Пробовал полностью копировать исходный код и добавлять enabled: false, тоже не помогло. Получилось только изменить фильтр:

"Document": {
	"FiltrationDocumentByAccount": {
		"ruleType": BusinessRuleModule.enums.RuleType.FILTRATION,
		"autocomplete": true,
		"autoClean": true,
		"baseAttributePatch": "Account",
		"comparisonType": Terrasoft.ComparisonType.EQUAL,
		"type": BusinessRuleModule.enums.ValueType.ATTRIBUTE,
		"attribute": "Account"
	},
	"FiltrationDocumentByContact": {
		"ruleType": BusinessRuleModule.enums.RuleType.FILTRATION,
		"autocomplete": true,
		"autoClean": true,
		"baseAttributePatch": "Account",
		"comparisonType": Terrasoft.ComparisonType.EQUAL,
		"type": BusinessRuleModule.enums.ValueType.ATTRIBUTE,
		"attribute": "Account"
	},
	"FiltrationDocumentByOpportunity": {
		"ruleType": BusinessRuleModule.enums.RuleType.FILTRATION,
		"autocomplete": true,
		"autoClean": true,
		"baseAttributePatch": "Account",
		"comparisonType": Terrasoft.ComparisonType.EQUAL,
		"type": BusinessRuleModule.enums.ValueType.ATTRIBUTE,
		"attribute": "Account"
	}
}

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

А если вместо правила надо вписать attributes с lookupListConfig, то у бизнес-правила всё равно приоритет выше :(
Как удалить бизнес-правило, чтобы срабатывал attributes?

Здравствуйте, Владимир!

Попробуйте следующий вариант:

getFilters: function() {
       var filters = this.callParent(arguments);
       filters.removeByKey("FiltrationDocumentByOpportunity");
       return filters;
}

спасибо, работает!

Кстати, только мне кажется нелогичным то, что в bpm есть отличная деталь ContactCareer, а повсюду Контакт фильтруется не по записям этой детали, а по полю Контрагент?

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

ContactCareer - развязочная таблица. У одного контакта может быть несколько работ. По этой причине не совсем логично фильтровать именно по этой таблице.

"Демьяник Алексей" написал:ContactCareer - развязочная таблица. У одного контакта может быть несколько работ. По этой причине не совсем логично фильтровать именно по этой таблице.

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

"Владимир Соколов" написал:

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

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

В таком случае, можно отключить базовые правила:smile:

"Демьяник Алексей" написал:Попробуйте следующий вариант:
getFilters: function() {
       var filters = this.callParent(arguments);
       filters.removeByKey("FiltrationDocumentByOpportunity");
       return filters;
}

знаете, как-то я поспешил... не работает это. поставил debugger - вижу, что функция getFilters совсем не вызывается

Здравствуйте, Владимир!

"Владимир Соколов" написал:

знаете, как-то я поспешил... не работает это. поставил debugger - вижу, что функция getFilters совсем не вызывается

Вы добавили данный код код в секцию methods: {}?

"Демьяник Алексей" написал:Вы добавили данный код код в секцию methods: {}?

Да. Он должен срабатывать при открытии карточки?

В карточке не должен, метод getFilters справедлив для секции.
Попробуйте удалить нужные Вам объекты правил в момент инициализации карточки:

onEntityInitialized: function() {
   this.callParent(arguments);
   delete this.rules.Document.FiltrationDocumentByOpportunity;
   delete this.rules.Document.FiltrationDocumentByAccount;
   delete this.rules.Document.FiltrationDocumentByContact;
},

"Щиголь Максим" написал:delete this.rules.Document.FiltrationDocumentByOpportunity;

Как я понимаю, Document - это название поля.

В моём случае
this.callParent(arguments);
delete this.rules.Contact.FiltrationContactByAccount;

ошибок никаких не получил, но и правило не деактивизировалось...

Здравствуйте, Владимир! Попробуйте способ:

 

"#название правила#": {
    "ruleType": 999
}

 

"Демьяник Алексей" написал:Попробуйте способ, описанный в этом комментарии.

Да, так правило отключается. Вроде, всё работает правильно :)

Можно заносить в Knowledge base

Владимир Соколов пишет:

Да, так правило отключается. Вроде, всё работает правильно :)Можно заносить в Knowledge base

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

Вот эта тема.

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

Evgi1980 пишет:

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

 

//Удаление\отключение бизнес правил:
"#название правила#": {
    "ruleType": 999
}
//Пример:
"Opportunity":{
   "FiltrationOpportunityByContact": {
       "ruleType": 999
   }
}

 

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

Добрый день!
Подскажите пожалуйста, как сделать доступ на детали таким же как и на родительские записи?
Права раздаются на каждую род. запись процессом.
В тройке для этого были группы, а в нет.
BPM 7.6

Нравится

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

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

"Александр Зубков" написал:

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

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

Создал отдельную тему, но здесь тоже спрошу - как скопировать права из родительской записи скопировать в объект детали?

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

После включения администрирования по записям, в системе появится объект SysDetailObjectNameRights.
Права на записи раздела хранятся в таблице SysSectionObjectNameRights.

Задача: при изменении записи в разделе перенести права на записи детали.

Решение:
1) Определите Id записей деталей:

select Id from SysDetailObjectName where SectionObjectNameId = 'Id измененной записи'

2) Удалите права на эти записи:

delete from SysDetailObjectNameRights
where RecordId in
(select Id from SysDetailObjectName where SectionObjectNameId = 'Id измененной записи')

3) Теперь Вам необходимо скопировать записи из таблицы SysSectionObjectNameRights в таблицу SysDetailObjectNameRights, изменив RecordId на Id записи детали.

"Демьяник Алексей" написал:После включения администрирования по записям, в системе появится объект SysDetailObjectNameRights.
Права на записи раздела хранятся в таблице SysSectionObjectNameRights.

А кроме того в системе есть таблицы SysAccountRight и SysAccountAddressRight. Их не трогать?

SysAccountRight - таблица, которая хранит права на записи в объекте Account (Контрагент).
SysAccountAddressRight - таблица, которая хранит права на записи в объекте AccountAddress (Адреса контрагента).

При раздаче прав необходимо переносить права с SysAccountRight в SysAccountAddressRight.

ЗЫ. Прошу прощения - в предыдущем посте указал некорректное название таблиц.

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

Добрый день,
Используя стандартный элемент БП "Страница редактирования" открываю страницу редактирования, создаю новую запись, указываю ей данные, проблема в следующем при создании состояние указываю из справочника "Не начата", но если пользователь при переходе на данный элемент изменяет какие нибудь другие поля и нажимает "Сохранить" активности автоматически присваивается состояние "Завершена", как это изменить?
По БП пользователь должен только ознакомится с данными и при необходимости их поправить, но состояние должно остаться "Не начата", т.к. это активность на следующий день

Нравится

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

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

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

Для решения Вашей задачи Вы также можете использовать следующую последовательность элементов:
1) Страница редактирования.
2) Изменить данные (меняем состояние задачи на "Не начата").
3) Промежуточный обрабатывающий сигнал - ожидаем изменение состояния активности на конечное.

Второе решение - использовать элемент "Задача".

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

Как запретить создание записи определенного типа (например, Контрагента) из Lookup, которое появилось в 7.6? Но при этом оставить возможность создавать из раздела.

lookup

Нравится

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

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

"Щиголь Максим" написал:Такой возможности нет

Это же насоздают пустых записей...

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