Есть обычная страница(карточка) раздела. Есть обычная деталь на этой странице. Нужно динамически при изменении одной записи на детали выводить итоговое значение всех записей детали на главной странице. Мот можно сделать БП который это проделывает, но нужно еще обновление страницы.
Вот есть похожая тема, но тут про реестр https://community.terrasoft.ua/forum/topic/10190

Нравится

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

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

Не получается, вот как делаю:
details: /**SCHEMA_DETAILS*/{
"UsrSplitbbf096611929": {
"schemaName": "UsrSplitDetail",
"entitySchemaName": "UsrSplit",
"filter": {
"detailColumn": "UsrInvoice",
"masterColumn": "Id"
},
subscriber: function() {
this.setMyFEnabled();
}
}
}

methods: {
setMyFEnabled: function() {
console.log("**test**");
}
}
В консоль ничего не выводит при изменении детали

Виталий, добавьте следующие методы в схему, в которой вызываете сабскрайбер:

subscribeDetailEvents: function(detailConfig, detailName) {
    this.callParent(arguments);
    var detailId = this.getDetailId(detailName);
    var detail = this.Terrasoft.deepClone(detailConfig);
    var sandbox = this.sandbox;
    sandbox.subscribe("DetailChanged", function(args) {
        return this.onDetailChanged(detail, args);
    }, this, [detailId]);
},
onDetailChanged: function(detail, args) {
    var subscriber = detail.subscriber;
    if (this.Ext.isFunction(subscriber)) {
        subscriber.call(this, args);
    } else if (this.Ext.isObject(subscriber)) {
        var methodName = subscriber.methodName;
        if (this.Ext.isFunction(this[methodName])) {
            this[methodName](args);
        }
    }
}

Без данных методов subscriber не работает во многих разделах системы.

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

Виталий, скопировал Ваш код в схему редактирования контактов - код не работает.
Добавил методы описанные выше - код успешно отрабатывает. Вот листинг кода:

"UsrTestTest": {
	"schemaName": "UsrSchema4Detail",
	"entitySchemaName": "UsrTestTest",
	"filter": {
		"detailColumn": "CreatedBy",
		"masterColumn": "Id"
	},
	subscriber: function(){
		this.test();
		debugger;
	}
}
methods: {
	test: function(){
		alert("!");
	},
	subscribeDetailEvents: function(detailConfig, detailName) {
		this.callParent(arguments);
		var detailId = this.getDetailId(detailName);
		var detail = this.Terrasoft.deepClone(detailConfig);
		var sandbox = this.sandbox;
		sandbox.subscribe("DetailChanged", function(args) {
			return this.onDetailChanged(detail, args);
		}, this, [detailId]);
	},
	onDetailChanged: function(detail, args) {
		var subscriber = detail.subscriber;
		if (this.Ext.isFunction(subscriber)) {
			subscriber.call(this, args);
		} else if (this.Ext.isObject(subscriber)) {
			var methodName = subscriber.methodName;
			if (this.Ext.isFunction(this[methodName])) {
				this[methodName](args);
			}
		}
	}
},

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

Вот что паказывает консоль когда меняю значение на детале:
"Method generatActiveRowControlsConfig is obsolete. Use generateActiveRowControlsConfig instead baseobject.js:85:5
Method handler is obsolete. Use click event instead"
Прилагаю схему:
invoicepage2.txt
Не судите строго за код, только разбираюсь в BPMonline

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

А может быть причина в том, что эта деталь - полноценный раздел, просто грид отображается?

Виталий, уточните, заработал ли subscriber? Данные сообщения в консоли никак не влияют на работу приложения. Если заработал, то Вам осталось в методе вызываемом сабскрайбером сделать запрос к базе данных используя entitySchemaQuery, а затем обновить поля основываясь на полученном результате. Для обновления полей воспользуйтесь методом this.set("Имя колонки", новое значение).

subscriber к сожалению не заработал, начал делать через sandbox. Даже что то получилось, в консоль удалось выводить пометки когда делаю изменения на детале, но передать в основную карточку никак не получается. Вот мой код:
invoicepage2.txt
Страница какбы загружается, но пишет "Загрузка" и все заблокировано.
Я уже не знаю что делать....

Добавил в onEntityInitialized строку this.callParent(arguments);и страница загрузилась но сообщение так и не ловит

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

Деталь это всего лишь редактируемый грид другого раздела, это все было создано до меня.
вод код детали:

define("UsrSplitDetail", ["terrasoft", "ConfigurationEnums", "ConfigurationGrid", "ConfigurationGridGenerator",
"ConfigurationGridUtilities"],
function(Terrasoft, configurationEnums) {
	return {
		entitySchemaName: "UsrSplit",
		attributes: {},
		methods: {
			onActiveRowSave: function() {
				this.sandbox.publish("Test1", { test: "param anything" }, [this.sandbox.id]);
				console.log("rowSelected in first detail..." + this.sandbox.id);
			}
		},
		messages: {
			"Test1": {
				mode: Terrasoft.MessageMode.PTP,
				direction: Terrasoft.MessageDirectionType.PUBLISH
			}
		}
	};
});

Сделал замещающую схему детали и там дописал нужный мне код.

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

Виталий, вот пример кода для детали с редактируемым реестром.

Страница контакта:

      messages: {
		"Test1": {
			mode: this.Terrasoft.MessageMode.PTP,
			direction: this.Terrasoft.MessageDirectionType.SUBSCRIBE
		}
      },
		methods: {
			init: function(){
				this.sandbox.subscribe("Test1", function() {
					alert("Great");
				}, this, ["111"]);
				this.callParent(arguments);
			}
		},

Деталь:

define("UsrSchema1Detail", ["ConfigurationGrid", "ConfigurationGridGenerator", "ConfigurationGridUtilities"], function() {
	return {
		entitySchemaName: "UsrTestTest",
		attributes: {
			"IsEditable": {
				dataValueType: Terrasoft.DataValueType.BOOLEAN,
				type: Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN,
				value: true
			}
		},
		details: /**SCHEMA_DETAILS*/{}/**SCHEMA_DETAILS*/,
		diff: [
			{
				"operation": "merge",
				"name": "DataGrid",
				"values": {
					"className": "Terrasoft.ConfigurationGrid",
					"generator": "ConfigurationGridGenerator.generatePartial",
					"generateControlsConfig": {"bindTo": "generatActiveRowControlsConfig"},
					"changeRow": {"bindTo": "changeRow"},
					"unSelectRow": {"bindTo": "unSelectRow"},
					"onGridClick": {"bindTo": "onGridClick"},
					"activeRowActions": [
						{
							"className": "Terrasoft.Button",
							"style": this.Terrasoft.controls.ButtonEnums.style.TRANSPARENT,
							"tag": "save",
							"markerValue": "save",
							"imageConfig": {"bindTo": "Resources.Images.SaveIcon"}
						},
						{
							"className": "Terrasoft.Button",
							"style": this.Terrasoft.controls.ButtonEnums.style.TRANSPARENT,
							"tag": "cancel",
							"markerValue": "cancel",
							"imageConfig": {"bindTo": "Resources.Images.CancelIcon"}
						},
						{
							"className": "Terrasoft.Button",
							"style": this.Terrasoft.controls.ButtonEnums.style.TRANSPARENT,
							"tag": "remove",
							"markerValue": "remove",
							"imageConfig": {"bindTo": "Resources.Images.RemoveIcon"}
						}
					],
					"initActiveRowKeyMap": {"bindTo": "initActiveRowKeyMap"},
					"activeRowAction": {"bindTo": "onActiveRowAction"},
					"multiSelect": false
				}
			}
		],
		mixins: {
			ConfigurationGridUtilites: "Terrasoft.ConfigurationGridUtilities"
		},
		methods: {
			int: function(){
				alert("!");
				this.callParent(arguments);
			},
			saveRowChanges: function(row, callback, scope) {
				scope = scope || this;
				callback = callback || this.Terrasoft.emptyFn;
				if (row && this.getIsRowChanged(row)) {
					scope.sandbox.publish("Test1", null, ["111"]);
					row.save({
						callback: callback,
						isSilent: true,
						scope: scope
					});
				} else {
					callback.call(scope);
				}
			}
		},
		messages: {
			"Test1": {
				mode: Terrasoft.MessageMode.PTP,
				direction: Terrasoft.MessageDirectionType.PUBLISH
			}
		}
	};
});

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

О дааа!!! Я сделал это!!! Оно сработало!!!
Но все-же есть где то список функций?
например:
saveRowChanges
init
onActiveRowSave
onEntityInitialized
и тд. Это намного упростило бы не жизнь .

Виталий, часть этих методов описана в миксине "ConfigurationGridUtilities", там описаны методы которые нужны для работы редактируемого грида. Остальные же описаны в BasePageV2 (init, onEntityInitialized).

Далее все как по маслу пошло, с entitySchemaQuery разобрался быстро, есть много примеров на комюнити, да и в отладке поиском найти можна

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

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

Правда работает. Опубликовал сообщение из onSaved. Спасибо

Добрый день.
Изменяю в редактируемом реестре данные, при помощи кода

 #5 Мотков Илья 6 апреля 2016 – 10:54 

У меня работает, но данные еще не сохранены в БД.
Подскажите может какой то еще метод есть которым могу воспользоваться, после добавления данных в БД ?

Марат, Вам необходимо смотреть в сторону замещения методов activeRowSaved (ConfigurationGridUtilities) в схеме детали или onSaved в карточке детали (в детали с редактируемым реестром он также вызывается).

Добрый день!
Подскажите как можно вытянуть данные из детали. Нужно выполнить расчёты на основании данных детали и поместить их на страницу реестра. использовать entitySchemaQuery? или же можно как то ещё получить значения?

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

Если данные присутствуют в реестре детали (уже отрисовались в гриде) - Вы можете их получить используя sandbox и атрибут GridData в схеме детали. Если же данных нет - только ESQ.

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

Добрый день!

Столкнулся со следующей проблемой. На гриде детали добавил поле числового типа с названием "MinPurchaseAmountEdit". Мне необходимо при переходе на эту страницу детали этому полю задавать некоторое значение. Делаю я это в событии "PageLoadComplete" (пробовал также в "Init"):

0

Код следующий:

Page.MinPurchaseAmountEdit.Value = 10m;

Компилируется всё отлично. Дебажится тоже. Присваиваемое значение "10" в формате "decimal" присваивается! Но, на самой странице в консоли возникает странное уведомление:

Uncaught ReferenceError: PageContainer_DetailGridContainer8021c0aacccf410e8f1da5c600f5d6ad_MinPurchaseAmountEdit is not defined

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

2

Я так ранее делал - всё получалось без проблем. Сейчас - не понятно поведение системы. Прошу помощи!

Нравится

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

Можно ещё попробовать присваивать значение контролу при помощи метода:

Page.MinPurchaseAmountEdit.SetValue(10m);

Или же писать в поле источника данных:

Page.DataSource.ActiveRow.SetColumnValue("MinPurchaseAmount", 10m);

Спасибо, Александр, что подсказали, но:
- в первом варианте ошибка та же: система не видит контрола на странице (та же ошибка в консоли браузера);
- во втором случае даже страница не открылась, а система выдала ошибку:

Exception Message: Ссылка на объект не указывает на экземпляр объекта.
Exception Type: System.NullReferenceException
Exception Source: TSBpm

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

3

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

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

У меня задача в том, чтобы заполнять это поле "MinPurchaseAmountEdit" данными из БД, и заполняться она должна в момент первого обращения к странице детали, а именно в момент перехода на неё после открытия карточки, к которой привязана деталь. Здесь событие смены записи на самом гриде или в основном реестре точно не подойдут.

Дело в том, что для всех записей этого грида значение "MinPurchaseAmountEdit" одинаково и мне нужно выводить это значение (если оно отлично от нуля!) и присваивать это значение контролу. Это всё при первом переходе на грид детали. Непонятно, почему кнопки, которые на этой детали находятся ("Добавить", "Изменить" и др.) обнаруживаются и на них система не ругается, а при добавлении контрола в этот же контейнер к кнопкам BPM его (контрол) не видит...

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

Page.MinPurchaseAmountEdit.SetValue(10m);

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

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

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

"они могут вызываться и при первом выборе записи." - но ведь поле должно обновляться при первичном открытии страницы этой детали. Неужели такой возможности нет в функционале BPM?

Сделал поле без привязки к БД:

4

Ошибка та же самая - система не видит моего контрола. Куда ещё "копать"?

P.S.: Значение "UId" на скринах разное, т.к. я удалял элемент, компилировал и добавлял новый такой же, чтобы убрать его привязку к БД, иначе система ругается - NullReferenceException...

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

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

Всё равно спасибо, Александр, что поучаствовали в обсуждении. Хорошего Вам дня!

Да, действительно странно. А Вы пробовали именно с полем ввода, если выводить в название кнопки или простой надписи, то отрабатывает нормально?

Попробовал добавить надпись с названием "Label1" и заголовком "Надпись 1", предварительно удалив поле ввода дробного числа и скомпилировав модуль. После этого в то же событие "PageLoadComplete" добавил код:

Page.Label1.Caption = "etqtert";

Когда скомпилировал модуль и открыл страницу детали, она открылась!!!! Но:

5

Вопрос: откуда там взялся контрол, который я до этого удалил - непонятно... И в структуре он тоже был. Но самое приятное то, что "Caption" у надписи поменялся (заметить по картинке трудно, но возможно)! При этом код:

Page.MinPurchaseAmountEdit.SetValue(10m);

был закомментирован.

Я удалил поле ввода дробного числа снова, удалил надпись, закомментировал код по переприсвоению "Caption" в надписи и раскомментировал код по установке значения в "MinPurchaseAmountEdit". Скомпилировал. Страница детали не открылась... :cry: Ошибка та же.

ВЫВОД: Изменение поля ввода дробного числа нельзя изменять ни в одном событии страницы до того пока она хотя бы один раз не прорисуется (ну или лыжи не едут...). Но это не применимо к остальным контролам. К сожалению(

А для поля ввода строки такое же самое поведение, что и для поля ввода числа?

Да, эти контролы ведут себя одинаково: поле ввода строки тоже не определено в событии "MinPurchaseAmountEdit". Ошибка та же.

Судя по сообщению:

Uncaught ReferenceError: PageContainer_DetailGridContainer8021c0aacccf410e8f1da5c600f5d6ad_MinPurchaseAmountEdit is not defined

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

Контрол идентифицируется браузером как:
http://i.piccy.info/i9/d0f1d2f7db16bc88df4890afcb8e71e5/1458115070/2764…

ПРИ ЭТОМ! Если никаких обращений к этому контролу ни в каком событии не писать, типа:

Page.MinPurchaseAmountEdit.SetValue(10m);

то, контрол система обнаруживает НОРМАЛЬНО! А если написать к нему обращение в виде предыдущего кода, то система разводит руками и говорит, что не знает, чего я от неё хочу. Похоже, она женского пола...

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

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

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

Нравится

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

Не знаю, насколько оптимален такой путь, но иногда я просто делаю VIEW с логикой внутри, затем регистрирую объект по этому VIEW, регистрирую деталь и уже использую на всю катушку.

Логика VIEW гораздо больше подаётся пониманию, к тому же её можно одновременно использовать в коде JS, в БП и в печатных формах.

Путь интересный.. а он возможен on-Demand? :) SqlExecutor позволяет создавать view?
На данный момент я разглядываю логику аналогичной детали с продажами, и пытаюсь понять ее логику, чтобы воспроизвести.. Но там как-то все нелинейно.. Подумаю насчет view.

"Шестаков Алексей Владимирович" написал:Путь интересный.. а он возможен on-Demand?

в bpm'online есть SQL-сценарии, которые позволяют в том числе создавать VIEW

Спасибо, такой вариант устраивает.

"Шестаков Алексей Владимирович" написал:SqlExecutor позволяет создавать view?

Он все позволяет, хоть drop :cool:

"Александр Кудряшов" написал:

Он все позволяет, хоть drop


А вот это уже настораживает :)

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

Всем привет, вот какая проблема:
Создал деталь в Мастере деталей. Потом решил переименовать ее, но там я не нашел как переименовать, только создавать новые. Удалив схему старой детали(скомпилировав) я начал создавать новую деталь, заполнив вкладку "Деталь" перешел на "Страницу" и повисло:

У кого какие идеи?

Нравится

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

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

можно попробовать так:

1. Сгенерировать код для требующих генерации
2. Компилировать измененное
3. зайти в схему где эта деталь находиться и в секции detail, проверить, чтобы не было ссылок на старую деталь.

Если не поможет- обратитесь в поддержку Terrasoft.

Показать все комментарии
предлагаю кнопку добавления записей на деталях показывать независимо от того, свернута она или нет, а при нажатии - добавлять запись тем или иным способом, развернув автоматом деталь
4 комментария

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

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

"Липатов Юрий Сергеевич" написал:добавление кнопки [Добавить], нарушит эту логику

каким образом? для добавления не требуется ничего показывать. И кроме того (например для редактируемого реестра), можно сначала развернуть и подгрузить (если была свернута), а потом запускать добавление.
Это экономит пользователю не только 1 клик, но и толику внимания, расходуемого на определение, свернута ли деталь или развернута и пуста.

В 7.7 уже лучше сделали различие между свёрнутой и развёрнутой деталью.

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

"Владимир Соколов" написал:с точки зрения логики

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

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

Здравствуйте, коллеги.

1) Нужно передать значение (Id выбранной записи) со страницы детали в страницу проекта, задействованной в бизнес процессе. Я так понял нужно использовать sandbox и messages. Подскажите подробнее как их использовать?

2) Добавил на деталь свою кнопку. Как по нажатию этой кнопки осуществить дальнейшее прохождение страницы проекта по бизнес процессу. Банальный this.acceptProcessElement(); не помогает.

Скриншот во вложении.

Нравится

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

Добрый день!

Посмотрите похожие темы на community. Подобные задачи уже решались.
http://www.community.terrasoft.ru/forum/topic/11626
http://www.community.terrasoft.ru/forum/topic/13314
http://www.community.terrasoft.ru/blogs/12691
http://www.community.terrasoft.ru/forum/topic/10554

Здравствуйте. С первым вопросом разобрался. Удалось передать сообщение по нажатию кнопки. Но это не удобно. Скажите, а можно передать сообщение по событию выделения записи в детали(событие типа onClick)? Функцию получения выделенной строки - this.getActiveRow() нашел. А где прописать событие не разобрался.

И еще вопрос по messages. Как отловить на основной странице, что сообщение из детали пришло? Т.е есть ли такое событие прихода сообщения?

Решил реализовать следующим образом: добавить кнопку в активную строку и по нажатию послать сообщение основной форме. В основной форме отловит сообщение и отправиться дальше по процессу. Что удалось найти:

Нашел на форуме, что можно добавить кнопку в активную строку.

{
	"operation": "insert",
	"name": "DataGridActiveRowTestAction",
	"parentName": "DataGrid",
	"propertyName": "activeRowActions",
	"values": {
		"className": "Terrasoft.Button",
		"style": Terrasoft.controls.ButtonEnums.style.BLUE,
		"caption": {"bindTo": "Resources.Strings.TestRowButtonCaption"},
		"visible": true,
		"tag": "call"
	}
}

И потом переопределить метод onActiveRowAction:

onActiveRowAction: function(buttonTag, primaryColumnValue) {
	switch (buttonTag) {
		// замещение базового метода посылаем сообщение основной странице
		case "call":
			this.sandbox.publish("GetContactDetailActiveRecordId", this.get("TestParameter"),       [this.sandbox.id]);
			break;
		default:
			this.callParent(arguments);
			break;
	}
},

Который объявлен в BaseSectionV2 (Базовая схема раздела).

Проблема:
1) при объявлении кнопки выходит сообщение, что DataGrid не является контейнером для других объектов. Подскажите, что делаю не так?

2) Как отловить в основной форме, что пришло сообщение из детали?
За ранее спасибо.

Добрый день!

Для получения идентификатора текущей записи детали в родительской карточке редактирования используя механизм подписки/публикации сообщений между соответствующими модулями - алгоритм будет примерно следующий:

Для начала необходимо в коде карточки и детали добавить адресное сообщение с одним и тем же названием, но в карточке с типом "Подписка", а в детали - с типом "Публикация". Например, для карточки редактирования:

messages: {
"GetContactDetailActiveRecordId": {
mode: Terrasoft.MessageMode.PTP,
direction: Terrasoft.MessageDirectionType.SUBSCRIBE
}
}

Для детали точно так же, только в свойстве direction необходимо указать Terrasoft.MessageDirectionType.PUBLISH.

Далее при инициализации карточки редактирования (метод init) нужно подписаться на это сообщение, а в функции обратного вызова получить значение из детали и сохранить его в атрибут модели карточки:

init: function() {
this.callParent(arguments);
this.sandbox.subscribe("GetContactDetailActiveRecordId", function(recordId) {
this.set("ContactDetailActiveRecordId", recordId);
}, this, [contactDetailSandboxId]);
}

Значение contactDetailSandboxId Вам необходимо определить самостоятельно (оно формируется в зависимости от названия детали). В коде детали оно хранится в свойстве this.sandbox.id.

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

onButtonClick: function() {
this.sandbox.publish("GetContactDetailActiveRecordId", this.get("ActiveRow"), [this.sandbox.id]);
}

Здравствуйте, Олег.
Да, все получилось именно так, спасибо.

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

Подскажите, как передать сообщение не по кнопке, а при выборе записи в DataGrid?

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

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

"Демьяник Алексей Олегович" написал: В случае выбора записи в DataGrid, сообщение будет генерироваться при выборе любой записи в любом гриде, что замедлит работоспособность системы.

Здравствуйте, Алексей.
Хорошо. Понял. Подскажите а можно кнопку в DataGrid встроить? И как?

Добрый день!

Для удобства вы можете добавить кнопку рядом с базовыми кнопками детали. Пример замещающей схемы детали во вложении.
addbuttontodetail.txt

Здравствуйте, Олег. Я так реализовал уже. Но это не совсем удобно. Подскажите как встроить кнопку в датагрид? В предыдущих версиях можно было. В крайнем случае, если нельзя, как кнопку в детали выделить? Другим цветом например?

Олег, добрый день!

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

в скрипте детали в блок diff добавить дополнительные свойства для DataGrid (название и заголовок кнопки привожу в качестве примера, Вы можете изменить их на свои):

{
	"operation": "merge",
	"name": "DataGrid",
	"values": {
		"activeRowAction": {"bindTo": "onActiveRowAction"},
		"activeRowActions": [
			{
				"className": "Terrasoft.Button",
				"style": this.Terrasoft.controls.ButtonEnums.style.BLUE,
				"markerValue": "myButtonAction",
				"tag": "myAction",
				"caption": "MyButton"
			}
		]
	}
}

После этого при выделении активной строки в детали должна появиться синяя кнопка с заголовком MyButton.

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

Далее в методах той же детали необходимо реализовать метод onActiveRowAction. Данный метод в качестве аргументов принимает тэг кнопки и значение ключевой колонки выделенной строки. Насколько я понял из предыдущих сообщений, Вам этой информации достаточно, но если необходимо получить какие-либо другие значения выделенной строки, можно вызвать метод this.getActiveRow(), который возвращает всю модель выделенной строки:

methods: {
	onActiveRowAction: function(buttonTag, primaryColumnValue) {
		if (buttonTag === "myAction") {
			// весь код ниже можно убрать, он демонстрирует, что значения
			// primaryColumnValue и activeRowId равны
			var activeRow = this.getActiveRow();
			var activeRowId = activeRow.get("Id");
			console.log(primaryColumnValue);
			console.log(activeRowId);
			// дальше Ваша реализация
			...
		}
	},
	...
}

Здравствуйте, Олег.
Спасибо. Получилось то, что нужно. Скрин во вложении.

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

Подскажите, как можно динамически подставлять в заголовок свёрнутой детали (например, адреса контрагента) признак (* или кол-во), если в детали есть данные?

Нравится

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

Добрый день!
стандартными средствами это реализовать не возможно.
Но, Вы можете, обладая знаниями программирования на JS, написать в принципе что угодно, к примеру найти нужный вам div и изменить его содержимое в зависимости от интересующих вас условий.

"Мотков Илья" написал:написать в принципе что угодно

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

Попробовали this.getGridData().collection.length

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

Проще будет на init или еще где-то написать запрос esq к объекту детали. (только не забыть фильтр по родительской записи).
В this.getGridData().collection.length не всегда будет храниться правильная информация,т.к. в деталь записи тянуться постранично. В указанном параметре будут храниться количество уже загруженных данных.

"Пащенко Александр Сергеевич" написал:только не забыть фильтр по родительской записи

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

Возможно, есть какое какое-то событие у детали, которое возникает при загрузке данных, и когда этот параметр будет уже соответствовать действительности?

Тогда есть смысл посмотреть в сторону атрибута IsGridEmpty и метода initIsGridEmpty.
Подробнее в GridUtilitiesV2

"Пащенко Александр Сергеевич" написал:Тогда есть смысл посмотреть в сторону атрибута IsGridEmpty и метода initIsGridEmpty.
Подробнее в GridUtilitiesV2

Спасибо!

Всё заработало!

"Пащенко Александр Сергеевич" написал:Тогда есть смысл посмотреть в сторону атрибута IsGridEmpty и метода initIsGridEmpty

Эх, я поторопился. Заработало только в том случае, если деталь развёрнута.
А когда деталь свёрнута, то IsGridEmpty не определяется (undefined).

В bpm для свёрнутой детали вообще не подчитываются никакие записи?

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

Для увеличения быстродействия данные на свернутую деталь действительно не загружаются. Загрузка данных осуществляется в момент разворачивания детали.
За загрузку данных отвечает метод loadGridData. Этот метод вызывается в момент разворачивания детали.

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

Важно! Не рекомендуется переопределять метод loadGridData, так как это замедлит быстродействие.

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

Для объекта была создана деталь. Можно ли блокировать кнопку Добавить (или скрывать ее) в зависимости от определенного условия?

Нравится

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

Иван,

Есть 2 метода, которые можно переопределить getAddRecordButtonVisible и getAddRecordButtonEnabled.

Я бы на вашем месте управлял доступностью и переопределил метод getAddRecordButtonEnabled на странице детали.

        methods: {
            /**
             * Возвращает доступность кнопки добавления записи.
             * overriden
             * @returns {boolean}
             */
            getAddRecordButtonEnabled: function () {
                return (2 == 5);
            }
        },

Добрый день.

Скрытие кнопки можно реализовать следующим образом:
В схеме детали, в разделе diff, добавить следующее:

			{
				"operation": "remove",
				"name": "addRecordButton"
			}

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

Юрий, такой подход, вероятно, не подойдет, потому что блокировать необходимо при некотором условии.

"Пажуков Иван Александрович" написал:            getAddRecordButtonEnabled: function () {
                return (2 == 5);
            }

Иван,

Можете скинуть скрипт страницы, на которую вы добавляете переопределение метода?

Дмитрий, могу скинуть.
pagescript.txt

Иван,

Вы изменяете страницу редактирования сущности "UsrNomMeterValues", а замещать метод нужно на странице детали данной сущности.

Поместил на страницу детали, результат тот же.
detailscript.txt

Иван, добрый день!

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

disableaddbutton.txt

После сохранения схемы необходимо очистить кэш браузера.

А в какой момент эта кнопка будет блокироваться? При открытии страницы? Или при изменении условия во время редактирования/сохранения страницы?

Доброго.
При открытии страницы.

Добрый день!

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

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

/**
 * @inheritdoc Terrasoft.BaseManyToManyGridDetail#getSchemaInsertQuery
 * @overridden
 */
getSchemaInsertQuery: function() {
	var insert = this.callParent(arguments);
	var detailColumnName = this.get("DetailColumnName");
	if (detailColumnName) {
		var detailColumnType = detailColumnName === "Contact" ?
				ServiceDeskConstants.ServiceObjectType.Contact :
				ServiceDeskConstants.ServiceObjectType.Account;
		insert.setParameterValue("Type", detailColumnType,
			this.Terrasoft.DataValueType.GUID);
	}
	return insert;
},
 
/**
 * @inheritDoc Terrasoft.BaseGridDetailV2#getAddRecordButtonVisible
 * @overridden
 */
getAddRecordButtonVisible: function() {
	return !Terrasoft.isCurrentUserSsp() && this.callParent(arguments);
},

 

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

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

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

Подскажите пожалуйста как реализовать вышеописанное.

Нравится

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

Коллеги, просьба помочь разобраться с деталями. Версия 7.6.

Ситуация: мы делим Заказы по типам (КП, Образцы, Коммерческий заказ) по причине удобного продуктового каталога.
Задача: хотим в карточке клиента вывести 3 детали и на каждую поставить фильтр по типу заказа. Разместил 3 детали через мастер раздела, он сгенерировал такой код:

        "Order": {
                "schemaName": "OrderDetailV2",
                "entitySchemaName": "Order",
                "filter": {
                        "detailColumn": "Account",
                        "masterColumn": "Id"
                },
                "filterMethod": "OrderFilter",
                "captionName": "OrderDetailCaption" // в локализируемых строках прописано "КП"
        },
        "Order1": {
                "schemaName": "OrderDetailV2",
                "entitySchemaName": "Order",
                "filter": {
                        "detailColumn": "Account",
                        "masterColumn": "Id"
                },
                "filterMethod": "Order1Filter",
                "captionName": "Образцы"
        },
        "Order2": {
                "schemaName": "OrderDetailV2",
                "entitySchemaName": "Order",
                "filter": {
                        "detailColumn": "Account",
                        "masterColumn": "Id"
                },
                "filterMethod": "Order2Filter",
                "captionName": "Заказы"
        }

Вручную прописал фильтрацию на деталях:

                        OrderFilter: function() {
                                var filterGroup = new this.Terrasoft.createFilterGroup();
                                filterGroup.logicalOperation = this.Terrasoft.LogicalOperatorType.AND;
                                filterGroup.add("OrderTypeFilter", this.Terrasoft.createColumnFilterWithParameter(
                                        this.Terrasoft.ComparisonType.EQUAL, "UsrOrderType", "358479b6-bf4b-46ed-93ee-5a8c558a0593") // КП
                                );
                                filterGroup.add("ByAccountFilter", this.Terrasoft.createColumnFilterWithParameter(
                                        this.Terrasoft.ComparisonType.EQUAL, "Account", this.get("Id"))
                                );
                                return filterGroup;
                        },
                        Order1Filter: function() {
                                var filterGroup = new this.Terrasoft.createFilterGroup();
                                filterGroup.logicalOperation = this.Terrasoft.LogicalOperatorType.AND;
                                filterGroup.add("OrderTypeFilter", this.Terrasoft.createColumnFilterWithParameter(
                                        this.Terrasoft.ComparisonType.EQUAL, "UsrOrderType", "21d5f440-ff74-4a89-8233-127facc90be4") // Образцы
                                );
                                filterGroup.add("ByAccountFilter", this.Terrasoft.createColumnFilterWithParameter(
                                        this.Terrasoft.ComparisonType.EQUAL, "Account", this.get("Id"))
                                );
                                return filterGroup;
                        },
                        Order2Filter: function() {
                                var filterGroup = new this.Terrasoft.createFilterGroup();
                                filterGroup.logicalOperation = this.Terrasoft.LogicalOperatorType.AND;
                                filterGroup.add("OrderTypeFilter", this.Terrasoft.createColumnFilterWithParameter(
                                        this.Terrasoft.ComparisonType.EQUAL, "UsrOrderType", "d8e59907-2b35-4429-bd14-2f5847dbf787") // Заказ
                                );
                                filterGroup.add("ByAccountFilter", this.Terrasoft.createColumnFilterWithParameter(
                                        this.Terrasoft.ComparisonType.EQUAL, "Account", this.get("Id"))
                                );
                                return filterGroup;
                        }

Однако нужного результата мы не получили:
1. Не изменились заголовки деталей (так и остались «Заказы»)
2. При нажатии на детали 1 и 2 разворачивается деталь 3, а нажимаемая остаётся без изменений
3. При переключении между вкладками карточки клиента произвольно меняются фильтры между деталями

Соответственно, вопросы:
1. Как изменить заголовок детали? Варианты "captionName": "OrderDetailCaption" (OrderDetailCaption – локализируемая строка) и "captionName": "Образцы" не срабатывают
2. Как сделать разворачивание / сворачивание деталей независимым друг от друга? Т.е. чтобы при разворачивании, к примеру, детали №2 разворачивалась она и только она, а детали №1 и №3 не менялись
3. Как зафиксировать условия фильтрации? Проблема в том, что при переключении вкладок карточка контрагента (Основная информация, Документы, История и т.п.) произвольно выставляются фильтры в деталях – то Образцы, то Заказ, то КП по одной и той же детали (хотя по ней жёстко прописан фильтр в коде)

Нравится

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

Чтобы не было описанной путаницы, я бы предложил сделать три разных клиентских модуля, в которых родителем указан OrderDetailV2, и прицепил бы их в качестве трех деталей. Код карточки у вас уже есть, останется только название schemaName новые прописать

Александр, честно говоря, не совсем понял, как это сделать. Но Ваша подсказка натолкнула на идею, которая сработала - просто создал 3 детали на основе объекта Заказ через мастер деталей, и разместил их на странице контрагента, далее прописал фильтры на каждую из них - и всё заработало! Спасибо

"Антон Кравченко" написал:просто создал 3 детали на основе объекта Заказ

Ну я это и предложил :)
Только вручную создать, хотя и с помощью мастера тоже можно

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