Вычисляемое поле для раздела

Здравствуйте! Встала задача добавить для сущности Заказы вычисляемое поле, которое представляет собой разность полей Итого (Amount) и Суперкомиссия (UsrSuperFee). Создал такое поле по примеру из документации. Но так как это поле заполняется только в модели при выполнении метода onEntityInitialized() при загрузке карточки редактирования заказа, появляется кнопка "Сохранить" для сохранения этого значения в базу. Если же вынести вычисляемое поле в раздел Заказов, то там в этом поле будут, естественно, одни нули, потому что метод onEntityInitialized() здесь не выполняется.

Подскажите, пожалуйста, как правильно готовить вычисляемые поля? Не нажимать же на кнопку "Сохранить" на каждом заказе, чтобы заполнить его!

Нравится

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

Добрый день Дмитрий!!!

по данной ссылки, что вы предоставили в своем обращение все правильно и верно описано как создать Вычисляемое поле. И в приведенном примере в документации Функция  this.calculateBalance исполняется в методе  onEntityInitialized для того чтобы при открытии карточки принудительно происходил расчет данного поля, что приведен в примере. Если вам этого не требуется выполнять а требуется чтобы расчет происходил, только к примеру при изменение какого-либо поля, то функцию  calculateBalance из метода  onEntityInitialized требуется исключить. И тогда при каждом открытии выполняться данная функция не будет. Или добавить условия при исполнение которого выполнялась бы данная функция.

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

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

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

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

Да, именно эту задачу мне требуется решить.

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

В [#Object#]SectionPageV2 нет метода onEntityInitialized(). По этой причине поле не считается, т.к. метод не вызывается.
В [#Object#]SectionPageV2 есть метод initData(), который Вы можете расширить для решения этой задачи.

"Демьяник Алексей" написал:В [#Object#]SectionPageV2 нет метода onEntityInitialized(). По этой причине поле не считается, т.к. метод не вызывается.

День добрый Алексей!!!

автор инцидента в первом своем сообщение давал ссылку на Академию, как в карточке редактирования создать и разместить вычисляемые поля. И именно данный метод "onEntityInitialized" есть в базовой и замещающих карточках редактирования. А потом желание перешло уже в раздел. Вот теперь я совсем запутался, что требуется Автору.

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

"Дмитрий Д." написал:Алексей, не подскажете, как из initData() получить доступ к коллекции элементов заказов раздела, чтобы вставить логику расчета разности двух полей и поместить его в третье?

Добрый день Дмитрий!!!

при инициализации раздела и получение Потока Данных у вас не получится выполнить заполнение Вычисляемого поля. Для этого вам требуется создать отдельный бизнес-процесс который при срабатывание определенных условий на входе пересчитывал бы Одно данное поле в базе данных, а в разделе вы бы уже видели результат. Но и данный метод я бы сказал является ошибочным, так как если в Таблице будет Миллион записей, то на пересчет потребуется очень огромное количество времени и ресурсов. Это неверный подход. В опубликованной Вами ссылке Как добавить вычисляемое поле описан алгоритм создания вычисляемого поля для карточки редактирования. Рекомендую именно в карточки редактирования разместить данное вычисляемое поле. А в разделе еще раз повторюсь отображать только результат вычисления.

В дополнении к рекомендации заполнять данные в карточке, могу предложить для случаев, когда в карточке поле еще не рассчитано, но в реестре уже хочется видеть эту информацию:
1. Вывести в реестр данную физическую колонку, которую вы будете вычислять в карточке.
2. В схеме реестра, переопределить метод «addItemsToGridData», который срабатывает при загрузке порции данных в реестр. Т.к. реестр не отображает миллион строк, а только небольшими порциями (по 15 строк) удовлетворяющими фильтрацию, плюс при прокрутке вниз. Так же загружает все порциями, и в этот момент так же срабатывает метод «addItemsToGridData».
3. В методе для незаполненных строк, производить любые вычисления, и заполнять любые существующие колонки. (Важно: данные не уйдут в БД, а будут только информационными. В БД запись делайте при работе с карточкой.)
Пример переопределения метода, в котором я читаю и меняю поле Title строк. По аналогии можно читать и менять любое поле:

addItemsToGridData: function() {
   this.callParent(arguments);
 
   var gridDataItems = this.getGridData().getItems();
   gridDataItems.forEach(function(item) {
      var oldTitle = item.get("Title");
      item.set("Title", oldTitle + "!!!");
   }, this);
 
   console.log("new items loaded");
}

P.S. Так же думая об оптимизации при прокрутке реестра, не забудьте анализировать что поле уже заполнено к примеру так: if (item.get("Title")) { тут логика } что бы не выполнять лишние операции.
В моем случае это не имеет смысла, Title у меня и так всегда заполнен, и пример исключительно тестовый.

Еще немного оптимизации, анализ в методе только новой добавочной (15 строк) коллекции, зачем бегать по всему реестру, если там уже все рассчитано:

addItemsToGridData: function(dataCollection, options) {
	// forEach only new
	dataCollection.getItems().forEach(function(item) {
		var oldTitle = item.get("Title");
		item.set("Title", oldTitle + "!!!");
	}, this);
 
	this.callParent(arguments);
	console.log("new items loaded");
}

Спасибо Максим. Идея очень интересная. Попробую у себя так же протестировать. Только вот вопрос, что будет если колонка "Title" не будет добавлена в Реестр раздела. Ошибка будет или нет выдаваться. Попробую протестировать. Ведь пользователь любит добавлять и удалять преднастроенные колонки.

Максим, спасибо! Уже близко к истине. Только, насколько я понимаю, item в методе addItemsToGridData есть ViewModel, поэтому если какой-либо столбец не выводится в разделе, доступ к нему посредством метода item.get() невозможен. В этом случае нужно будет получать значения полей запросом к базе.

И еще: есть ли способ (может, с помощью скрипта?) рассчитать значения нового поля на основе существующих данных для всех записей раздела Заказы разом?

Благодарю.

"Дмитрий Д." написал:И еще: есть ли способ (может, с помощью скрипта?) рассчитать значения нового поля на основе существующих данных для всех записей раздела Заказы разом?

Добрый день Дмитрий!!!

как решить вашу задачу описал Илья Мотков в следующем инциденте. Последняя активность в реестре контрагентов посмотрите пожалуйста и по аналогии можно решить и вашу задачу.

Да, там всегда есть ID записи, по которой можно сделать esq, но в этом мало смысла, так как есть метод «initQueryColumns», который и определяет список загружаемых в модель колонок.
Можно заставить загружаться все колонки в модель, что несколько замедлит загрузку реестра:

initQueryColumns: function(esq) {
	this.callParent(arguments);
	this.addAllColumns(esq);
}

Либо по аналогии с реестром звонков, добавить только те колонки, что вам нужны:

initQueryColumns: function(entitySchemaQuery) {
   this.callParent(arguments);
   if (!entitySchemaQuery.columns.contains("IntegrationId")) {
      entitySchemaQuery.addColumn("IntegrationId");
   }
},

Разом изменить все существующие записи, можете либо бизнес процессом, либо SQL запросом.
В первом случае логику будете писать на C#, во втором на Transact-SQL.
Это если вы имеете в виду все-все существующие записи, а не только те, что выведены в реестр. И имеете в виду физические данные в базе данных, а не только информационно в реестре. Так как напоминаю, что в реестр данные грузятся порционно.

"Щиголь Максим" написал:Разом изменить все существующие записи, можете либо бизнес процессом, либо SQL запросом.
В первом случае логику будете писать на C#, во втором на Transact-SQL.

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

Можете подсказать пример написания и выполнения SQL-скрипта в bpm'online 7.7? Что-то не нахожу подобного в документации.

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

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

"Дмитрий Д." написал:

Можете подсказать пример написания и выполнения SQL-скрипта в bpm'online 7.7? Что-то не нахожу подобного в документации.

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

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

"Дмитрий Д." написал:Собственно, необходимо для каждого Order вычесть из поля Amount поле UsrSuperFee и вставить результат в поле UsrAmountWithSuperFee.

вот Дмитрий сам запрос на обновление

update p set
p.UsrAmountWithSuperFee = p.Amount - p.UsrSuperFee
from Order as p

Спасибо, Алексей и Михаил, за помощь!
Я так решил: если нужно, чтобы вычисляемое поле объекта получало значение в зависимости от значений других полей, то сначала необходимо прогнать всю таблицу sql-запросом для заполнения вычисляемого поля, а уже в карточке редактирования объекта реализовывать логику пересчета его значения при необходимости.

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