Добрый день,

Есть несколько преднастроенных страниц (использую в БП). Необходимо настроить валидацию определенных полей (напр. только цифры).

Пробовала настроить по аналогии с валидацией на странице раздела, но на преднастроенной странице валидация не срабатывает.

Явно, я что-то упускаю срецифическое для преднастроенных страниц? Просьб направить в правильном направлении.

Пример метода, которй я использую:

            setValidationConfig: function() {

               this.addColumnValidator("CrpINN", this.innValidator);

            },

                innValidator: function(value) {

                var invalidMessage = "";

                var isValid = true;

                var number = value || this.get("CrpINN");

                isValid = (Ext.isEmpty(number) ||

                    new RegExp("^[0-9]{8}$").test(number));

                if (!isValid) {

                    invalidMessage = this.get("Resources.Strings.InvalidINNCodeFormat");

                }

                return {

                    invalidMessage: invalidMessage

                };

            },

      

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

 

 

Нравится

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

судя по всему проблема в том, что преднастроенная страница и обычная страница раздела унаследованы от разных родителей. Следовательно в зависимости преднастроенной нужно добавить тот модуль, в котором реализован функционал валидации. Беглым поиском нашел BaseSchemaViewModel, однако не уверен на 100%.

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

Вадим Косарев,

 Спасибо! Я обязательно разберусь с зависимостями.

 

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

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

Все оказалось гораздо проще  - для преднастроенной страницы необходимо указать поле+сослаться на основную страницу. Все заработало.

 

setValidationConfig: function() {

             this.addColumnValidator("CrpPortalProductRequest1.CrpINN", this.innValidator);

            },

                innValidator: function(value) {

                

                var invalidMessage = "";

                var isValid = true;

                var number = value || this.get("CrpPortalProductRequest1.CrpINN");

            

                isValid = (Ext.isEmpty(number) ||

                    new RegExp("^[0-9]{8}$").test(number));

                if (!isValid) {

                    invalidMessage = this.get("Resources.Strings.InvalidINNCodeFormat");

                }

                return {

                    invalidMessage: invalidMessage

                };

            },

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

Добрый день. Применил валидацию даты согласно статье https://academy.terrasoft.ru/documents/technic-sdk/7-15/dobavlenie-validacii-k-polyu-stranicy

Всё работает хорошо. Но при удалении значения  поля почему, то распознаёт что не проходит валидацию. 

У меня поле желаемая дата не должна быть меньше текущей даты и времени или должно быть пусто. Пустым полем он не даёт сохранить. Скрин вложил. 

https://i.imgur.com/H9hksBj.png

 

Вот код:

// Метод-валидатор значения колонок [UsrCustomDate] и [CreatedOn].

            dueDateValidator: function() {

                // Переменная для хранения сообщения об ошибке валидации.

                var invalidMessage = "";

                // Проверка значений колонок [UsrCustomDate] и [CreatedOn].

                if (this.get("UsrCustomDate") < this.get("UsrDateReal"))  {

                    // Если значение колонки [UsrCustomDate] меньше значения колонки [CreatedOn], 

                    // в переменную invalidMessage помещается значение локализуемой строки с сообщением

                    // об ошибке валидации.

                    invalidMessage = this.get("Resources.Strings.CreatedOnLessDueDate");

                }

        

                // Объект, свойство которого содержит сообщение об ошибке валидации.

                // Если валидация прошла успешна, в объекте возвращается пустая строка.

                return {

                    // Сообщение об ошибке валидации.

                    invalidMessage: invalidMessage

                };

            }

Нравится

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

Если в базе в поле Null, не факт, что в переменной JS тоже так. добавьте вывод в лог, посмотрите что там, а затем можно будет вписать в условие if проверку на такое значение.

Не смотрели, что попадает в переменную при очистке? Может, там как раз минимальная дата, вроде 01.01.01? Или оба сравниваемые поля пустые, их значения одинаковы и строгое сравнение при помощи «<» даёт отрицательный ответ? Попробуйте отладиться или просто выводить в консоль значение полей и результаты проверки.

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

Насколько я понял NULL. А NULL это меньше текущей даты. Можно ли 

        if (this.get("UsrCustomDate") < this.get("UsrDateReal")) как то изменить.? Чтобы принимал тоже NULL.

 

 

Если в базе в поле Null, не факт, что в переменной JS тоже так. добавьте вывод в лог, посмотрите что там, а затем можно будет вписать в условие if проверку на такое значение.

Я по трассировке проверил почему то window.console.log(); ничего не возвращает. 

  if (this.get("UsrCustomDate") < this.get("UsrDateReal"))  {

                      if (this.get("UsrCustomDate") !== null)  {

                    // Если значение колонки [UsrCustomDate] меньше значения колонки [CreatedOn], 

                    // в переменную invalidMessage помещается значение локализуемой строки с сообщением

                    // об ошибке валидации.

                    invalidMessage = this.get("Resources.Strings.CreatedOnLessDueDate");

                }

                }

 

А есть ли текущее значение, а то я через бизнес-процессы обновляю всегда поле UsrDateReal???

В JS текущую дату и время можно узнать при помощи присвоения или сравнения с new Date().

Я проще нашёл решение. Просто к сравнительному полю привязал системную переменную текущая дата https://i.imgur.com/Xf3bcEA.png.&nbsp;

С new Date() нужно было попотеть по моему. 

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

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

Предлагаю создать пользовательскую настройку проверок перед сохранением карточки.

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

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

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

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

Добрый день, Владимир.

Ваша идея может быть составляющей более общей, которая подавалась ранее:

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

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

Cделан запрос в базу данных из клиентского модуля для получения системной настройки: 

this.Terrasoft.SysSettings.querySysSettingsItem("PsMaximumProgramsCount", function(value) {
	countSettings = value;
}, this);

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

message - сообщение для поля валидации;

periodicity  - выпадающий список (словарь) в котором есть значение "Ежедневно";

countSettings  - ранее полученное значение системной настройки;

concertProgramsCount - количество записей в таблице;

var periodicity = "";
if (this.get("PsPeriodicity")) {
	periodicity = this.get("PsPeriodicity").displayValue;
}
var esq = Ext.create("Terrasoft.EntitySchemaQuery", {
	rootSchemaName: "PsConcertPrograms"
});
esq.addColumn("PsPeriodicity.Name", "PsPeriodicityName");
var esq1Filter = esq.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL,
	"PsPeriodicity.Name", "Ежедневно");
esq.filters.add("esq1Filter", esq1Filter);
esq.getEntityCollection(function(result) {
	var message = "";
	if (result.success) {
		var concertProgramsCount = result.collection.collection.length;
		if (periodicity === "Ежедневно" && concertProgramsCount <= countSettings ) {
			message = this.get("Resources.Strings.PsFewFreeConcertHalls").replace("NNN", countSettings);
		}
	}
	return message;
}, this);

Вывод валидации для поля и при сохранении страницы:

concertHallsValidator: function(message) {
	var invalidMessage = message;
	return {
		fullInvalidMessage: invalidMessage,
		invalidMessage: invalidMessage
	};
}

Проблема в том что по отдельности все работает, но когда вместе - вступает в дело асинхронность и все идет не по очереди, а если использую через callback тогда застреваю на замыкании.

Спасибо всем кто окажет помощь в решении проблемы.

Нравится

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

Prime Source,

нет. стоп. я думал вы прогоняете esq в onEntityInitialized, а потом используете this.$PeriodValidationMessage для проверки. тогда такие варианты:

1) на изменение поля PsPeriodicity запускаете concertHallsValidator. Изменяете this.addColumnValidator("CreatedOn", this.MessageValidator);

2) Используете asyncValidate (вроде так называется метод)

И уберите return. Ну не используется он в асинхронных функциях)

немного не понимаю смысла return из async функции, поэтому вариант такой:

в attributes добавляете 

"PeriodValidationMessage": {
	dataValueType: 1,
	value: ""
}

esq:

var periodicity = "";
if (this.get("PsPeriodicity")) {
	periodicity = this.get("PsPeriodicity").displayValue;
}
var esq = Ext.create("Terrasoft.EntitySchemaQuery", { rootSchemaName: "PsConcertPrograms" });
esq.addColumn("PsPeriodicity.Name", "PsPeriodicityName");
esq.filters.addItem(esq.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL, "PsPeriodicity.Name", "Ежедневно"));
esq.getEntityCollection(function(result) {
	if (result.success) {
		var concertProgramsCount = result.collection.collection.length;
		//считывание сист. настройки
		Terrasoft.SysSettings.querySysSettingsItem("PsMaximumProgramsCount", function(countSettings) {
			//сравнение
			if (periodicity === "Ежедневно" &amp;&amp; concertProgramsCount &lt;= countSettings ) {
				this.$PeriodValidationMessage = this.get("Resources.Strings.PsFewFreeConcertHalls").replace("NNN", countSettings);
			}
 
		}, this);
	}
}, this);

валидация

concertHallsValidator: function(message) {
	var invalidMessage = this.$PeriodValidationMessage;
	return {
		fullInvalidMessage: invalidMessage,
		invalidMessage: invalidMessage
	};
}

 

Добрый день,

Каждый борется с асинхронностью своими средствами :)

Как вариант, можно вложить одно в другое: выполнять запросы по очереди, по мере получения ответа из БД. Например перенести вашу логику с esq запросом в колбэк системной настройки.

Тёскин Дмитрий Валерьевич,

 

Пробовал, тогда return возвращает поздно ответ

concertHallsValidator:  function(){
	var periodicity = "";
	if (this.get("PsPeriodicity")) {
		periodicity = this.get("PsPeriodicity").displayValue;
	}
	this.Terrasoft.SysSettings.querySysSettingsItem("PsMaximumProgramsCount", function(countSettings) {
		var esq = Ext.create("Terrasoft.EntitySchemaQuery", {
			rootSchemaName: "PsConcertPrograms"
		});
		esq.addColumn("PsPeriodicity.Name", "PsPeriodicityName");
		var esq1Filter = esq.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL,
			"PsPeriodicity.Name", "Ежедневно");
		esq.filters.add("esq1Filter", esq1Filter);
		esq.getEntityCollection(function(result) {
			var invalidMessage = "";
			if (result.success) {
				var concertProgramsCount = result.collection.collection.length;
				if (periodicity === "Ежедневно" &amp;&amp; concertProgramsCount &gt; countSettings ) {
					invalidMessage = this.get("Resources.Strings.PsFewFreeConcertHalls").replace("NNN", countSettings);
				}
			}
			return invalidMessage;
		}, this);
	}, this);
},
setValidationConfig: function() {
	this.callParent(arguments);
	this.addColumnValidator("PsPeriodicity", this.concertHallsValidator);
}

 

Варфоломеев Данила,

Асинхронность не дает

methods: {
	concertHallsValidator:  function(callback){
		var periodicity = "";
		if (this.get("PsPeriodicity")) {
			periodicity = this.get("PsPeriodicity").displayValue;
		}
		var esq = Ext.create("Terrasoft.EntitySchemaQuery", { rootSchemaName: "PsConcertPrograms" });
		esq.addColumn("PsPeriodicity.Name", "PsPeriodicityName");
		esq.filters.addItem(esq.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL, "PsPeriodicity.Name", "Ежедневно"));
		esq.getEntityCollection(function(result) {
			if (result.success) {
				var concertProgramsCount = result.collection.collection.length;
				//считывание сист. настройки
				Terrasoft.SysSettings.querySysSettingsItem("PsMaximumProgramsCount", function(countSettings) {
					//сравнение
					if (periodicity === "Ежедневно" &amp;&amp; concertProgramsCount &lt;= countSettings ) {
						this.$PeriodValidationMessage = this.get("Resources.Strings.PsFewFreeConcertHalls").replace("NNN", countSettings);
					}
					return callback.call(this);
				}, this);
			}
		}, this);
	},
	MessageValidator: function() {
		var invalidMessage = this.$PeriodValidationMessage;
		return {
			fullInvalidMessage: invalidMessage,
			invalidMessage: invalidMessage
		};
	},
	setValidationConfig: function() {
		// Вызывает инициализацию валидаторов родительской модели представления.
		this.callParent(arguments);
		this.addColumnValidator("CreatedOn", this.concertHallsValidator(this.MessageValidator));
	}
},
			}

 

Prime Source,

нет. стоп. я думал вы прогоняете esq в onEntityInitialized, а потом используете this.$PeriodValidationMessage для проверки. тогда такие варианты:

1) на изменение поля PsPeriodicity запускаете concertHallsValidator. Изменяете this.addColumnValidator("CreatedOn", this.MessageValidator);

2) Используете asyncValidate (вроде так называется метод)

И уберите return. Ну не используется он в асинхронных функциях)

Варфоломеев Данила,

 

Спасибо большее, помогло отлично asyncValidate. Раньше не знал что этот метод. Вод такой код заработал отлично:

asyncValidate: function(callback, scope) {
	this.callParent([function(response) {
		if (!this.validateResponse(response)) {
			return;
		}
		Terrasoft.chain(
			function(next) {
				this.validateConcertHalls(function(response) {
					if (this.validateResponse(response)) {
						next();
					}
				}, this);
			},
			function(next) {
				callback.call(scope, response);
				next();
			}, this);
	}, this]);
},
validateConcertHalls: function(callback, scope) {
	Terrasoft.SysSettings.querySysSettingsItem("PsMaximumProgramsCount", function(countSettings) {
		var periodicity = "";
		var result = {success: true};
		if (this.get("PsPeriodicity")) {
			periodicity = this.get("PsPeriodicity").displayValue;
		}
		var esq = Ext.create("Terrasoft.EntitySchemaQuery", { rootSchemaName: "PsConcertPrograms" });
		esq.addColumn("PsPeriodicity.Name", "PsPeriodicityName");
		esq.filters.addItem(esq.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL, 
			"PsPeriodicity.Name", "Ежедневно"));
		esq.getEntityCollection(function(response) {
			if (response.success &amp;&amp; periodicity === "Ежедневно" &amp;&amp; (!this.isAddMode() &amp;&amp; 
				response.collection.getCount() &gt; countSettings) || (this.isAddMode() &amp;&amp; 
				response.collection.getCount() &gt;= countSettings)) {
					result.message = this.get("Resources.Strings.PsFewFreeConcertHalls").replace("NNN", countSettings);
					result.success = false;
			}
			callback.call(scope || this, result);
		}, this);
	}, this);
}

 

Prime Source,

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

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

Добрый день!



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

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

Нравится

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

Владимир, добрый день.

Для примера рассмотрим реалзиацию для объекта Обращения.

Одним из возможных вариантов реализации будет следующий:

1.На странице [Обращения], открыть мастер раздела и во вкладке [Решение и закрытие], добавить новое текстовое поле типа "Строка"

Например с названием "Причина перехода на следующую стадию" http://prntscr.com/i97vb7

2.Перейдя в мастере раздела на [Бизнес правила], создадим новое БП  http://prntscr.com/i97viu

Это правило говорит, что при изменении состояния обращения с "Новое" на "В работе",

поле "Причина перехода на следующую стадию" является обязательным к заполнению.

Обращаем Ваше внимание, что при создании БП в графе [Какое поле делать обязательным] следует указать название требуемой к заполнению строки из БД http://prntscr.com/i97vvk

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

он будет получать уведомление о том, что не заполнено обязательное поле указания причины http://prntscr.com/i97w4x&nbsp;

При переходе по actiondashboard'у выполняется сохранение записи и валидация заполненных полей.

Спасибо, Андрей!



При реализации возникла проблема в связи с различиями в поведении ActionsDashboard и lookup-поля:



Имеется справочник QualifyStatus, он выведен на страницу LeadPageV2 через ActionDashboard, в разделе attributes страницы указаны дополнительные колонки кроме id и value:

"QualifyStatus": {

    lookupListConfig: {

        columns: ["Name", "StageNumber", "UsrIsTaken", "UsrIsOpportunity", "UsrIsDisqualified"]

    }

}

Но они не доступны в коде страницы работы через this.get("QualifyStatus"). Если же добавить на страницу Lookup с QualifyStatus и работать со справочником через него то данные поля становятся доступны

Кроме того, при неудачной валидации статус на ActionsDashboard перескакивает обратно, что не совсем логично

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

Т.е. this.get("QualifyStatus") возвращает объект в котором нет указанных колонок?

Именно 

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

Мне не удалось воспроизвести ваш кейс все корректно отрабатывает. Так что проблема не в коробке. Рекомендую проанализировать состояние объекта сразу после инициализации схемы и в момент вашего вызова, может «по пути» затираются его свойства.

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

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

1. Есть раздел "Подписанты" с полями:

    ФиоКонтакта, РазрешеннаяСумма

    

2. Есть раздел "Договора" с полями

    СуммаДоговора

    ФиоПодписанта = Подписанты.ФиоКонтакта

    

Необходимо произвести валидацию полей на схеме раздела "Договора"

    СуммаДоговора < Подписанты.РазрешеннаяСумма 

где Договор.ФиоПодписанта = Подписанты.ФиоКонтакта

По примерам https://academy.terrasoft.ru/documents/technic-sdk/7-10/postroenie-putey-k-kolonkam-otnositelno-kornevoy-shemy и https://academy.terrasoft.ru/documents/technic-sdk/7-10/poluchenie-rezultata-zaprosa  построил свой запрос 

            

methods: {
	// Метод-валидатор значения 
	SummValidator: function() {
		var message = "";
		// Создаем экземпляр класса Terrasoft.EntitySchemaQuery с корневой схемой [Contact].
		var esq = this.Ext.create("Terrasoft.EntitySchemaQuery", {
			rootSchemaName: "UsrContract1Page"
		});
		// Добавляем колонку 
		esq.addColumn("UsrLimitAmount2.[UsrSignatories1Page:Id:UsrSignatoriesId].UsrLimitAmount",
			"UsrSignatoriesLimitAmount");
		// Получаем одну запись из выборки по [Id] объекта карточки и отображаем ее
		// в информационном окне.
		esq.getEntityCollection(function(result) {
			if (!result.success) {
				// обработка/логирование ошибки, например
				this.showInformationDialog("Ошибка запроса данных");
				return;
			}
			result.collection.each(function(item) {
				message += item.get("UsrSignatoriesLimitAmount");
			});
			this.showInformationDialog(message);
		}, this);
	},			
	// Переопределение базовой функции, инициализирующей пользовательские валидаторы.
	setValidationConfig: function() {
		// Вызывает инициализацию валидаторов родительской модели представления.
		this.callParent(arguments);				
		this.addColumnValidator("UsrLimitAmount2", this.SummValidator);
		this.addColumnValidator("UsrContractAmount", this.SummValidator);
	}
},

Но при проверке работы проваливаюсь в ошибку this.showInformationDialog("Ошибка запроса данных");

Помогите с решением данного кейса

Нравится

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

 

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

И это еще не все, далее в вашем методе валидаторе не предусматривается логика возвращение объекта, со строго установленными свойствами

{
   fullInvalidMessage: invalidMessage,
   invalidMessage: invalidMessage
};

которые там обязаны быть внимательно ознакомьтесь с примером https://academy.terrasoft.ru/documents/technic-sdk/7-10/dobavlenie-validacii-k-polyu-stranicy

PS: для валидации поля использовать запрос в БД каждый раз - с точки зрения архитектуры и перфоманса не хорошо, подумайте как вы могли бы предварительно подготовить данные необходимые для валидации, заодно и избежите асинхронного вызова.

 

 

 

Лог консоли:

Севостьянов Илья Сергеевич пишет:

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

Есть на схеме Договора поле типа Справочник имеющее ссылку в раздел Подписанты. Но тут скорей отсутствие навыка разработки в BPM - как подставить сумму в это поле в зависимости от выбранного Подписанта? Как-то "костыльно" получится...

как подставить сумму в это поле 

в это же поле ? в справочное - никак.

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

Ответ supporta:

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

Примеры реализаций таких атрибутов множество в базовых схемах, поищите. Используются они как обычные колонки, следовательно их можно будет устанавливать this.set и читать this.get, и, использовать их в валидации.

Вам необходимо создать атрибут для вашей «РазрешеннаяСумма»

Далее данный атрибут нужно будет заполнять как при инициализации карточки, метод, onEntityInitialized: function() {

Так и при изменении лукапов от которых зависит получаемая информация. В вашем случае при изменении лукапа "ФиоПодписанта"

И последнее, как получить данные которыми вы хотите заполнить данный атрибут: Как вы правильно поняли, с помощью esq, ссылку на статью которой вы предоставили второй. Вам достаточно сделать запрос к корневой таблице «Подписанты» с условием ФиоКонтакта = this.get(“ФиоПодписанта”)



 

Севостьянов Илья Сергеевич,

Последовал совету supporta и вот что у меня получилось:

1. Создал виртуальную колонку в атрибутах

2. В onEntityInitialized  вызываю функцию setVirtLimitAmount с использованием EntitySchemaQuery для чтения данных из БД

3. dueSummValidator - проверяю значения и setValidationConfig - вызываю инициализацию валидаторов

4. Все это работает, но я бы сказал через одно место... работает синхронно, а мне бы хотелось асинхронно... По сути для этого мне было бы достаточно, каждый раз при изменении Подписанта (UsrSignatories) вызывать функцию setVirtLimitAmount. Возможно ли отследить изменение поля UsrSignatories? Одного Lookup-а недостаточно.

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

Добрый день, коллеги!

Понадобилось реализовать следующий кейс - При добавлении участника встречи необходимо проверять, не задействован ли он в это время на другой встрече. Поскольку добавление участника - вставка записи в объект ActivityParticipant, решено было добавить в этот объект событийный подпроцесс, запускающийся по сигналу ActvityParticipantSaving. В событийном подпроцессе после сигнала идет скрипт, который будет делать запросы в базу и проверять пересечения с другими активностями нужного типа, после чего будет возвращать Id активности, в которой задействован этот участник, если нашелся конфликт, или просто null, если конфликтов не найдено. После этого встает несколько подзадач:
1) Как запретить при нахождении конфликта дальнейшее сохранение записи в базу;
2) Как вывести пользователю окно с ссылкой на активность, которая вызывает конфликт;
3) Как продолжить сохранение в нормальном режиме, если конфликт не найден.

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

Система sales enterprise 7.9.2

Нравится

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

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

Подобный кейс обсуждался еще здесь:
http://www.community.terrasoft.ru/forum/topic/9994#comment-43946
Не смотрите, что скрин из пятерки, логика ровно та же - если активностей в указанное время не найдено - сгенерировать событие, если нет - передать id встречи на клиент, и там уже сформировать ссылку на проблемную активность. Пример создания ссылки можно подсмотреть в createLink из GridUtilitiesV2, либо же просто захардкодить. После чего показать данную ссылку.

Добрый день, Илья!

Можно пожалуйста поподробнее, какое именно событие надо сгенерировать, чтобы продолжить сохранение в штатном режиме? Если я правильно понял из приложенной статьи, нужно просто сгенерировать опять то же событие, что и вызывает мой скрипт, это так? Если это событие в моем скрипте не будет сгенерировано, т.е. подпроцесс пойдет по второй ветке, запись не будет сохранена? Как из C# кода подпроцесса передать id встречи на клиента, через публикацию сообщения, а в схеме его ловить? Если да, то где можно посмотреть пример генерации сообщения для клиента из серверного кода?

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

Олег, по Вашим вопросам:

1) Да, то же событие
2) Да, не будет сохранена, так как фактически Вы заместите логику обработки сообщения
3) Да, есть отличный класс MsgChannelUtilities, у которого есть такие методы:

public static void PostMessage(UserConnection userConnection, string senderName, string messageText)
 
public static void PostMessageToAll(string senderName, string messageText)

Итого, в C# отправляем сообщение:

MsgChannelUtilities.PostMessage(UserConnection, "LimitBudget", accountId.ToString());

В JS на клиенте подписываемся на него и обрабатываем:

init: function(callback, scope) {
    this.Terrasoft.ServerChannel.on(Terrasoft.EventName.ON_MESSAGE, this.onMessage, this);
},
 
onMessage: function(scope, message) {
if (message.Header.Sender === "LimitBudget") {
// do something
     }
},
 
destroy: function() {
    this.Terrasoft.ServerChannel.un(Terrasoft.EventName.ON_MESSAGE, this.onMessage, this);
    this.callParent   (arguments)
}

Добрый день!

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

Процесс "ActivityEventProcess" остановлен. Превышено максимальное количество повторений элемента "Activity Saving". Если я правильно понимаю, то генерация такого же сообщения, по которому запускается подпроцесс, зацикливает его. Я точно правильно понял, какое сообщение нужно генерировать?

Здравствуйте, вашу задачу проще и корректней сделать на уровне JS, там же и выводить сообщение пользователю, а запросы в БД делать асинхронно. Данный алгоритм с асинхронной валидацией обсуждался в этой теме:
http://www.community.terrasoft.ru/forum/topic/25300#comment-67748

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

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

Добрый день.
Версия 7.9.0

Пробую добавить валидацию полей в редактируемую деталь с реестром и вычислаемы полями по примеру
https://academy.terrasoft.ru/documents/technic-sdk/7-9/dobavlenie-valida...

Но пример для страницы редактирования раздела. Может я не в ту схему вставляю методы? Или же я просто не вижу ошибку которую допускаю ? Буду признателен за подсказку

 

define("UsrUsrOrderOnField1Page", [], function() {
        return {
                entitySchemaName: "UsrOrderOnField",
                details: /**SCHEMA_DETAILS*/{}/**SCHEMA_DETAILS*/,
                attributes: {
                        "UsrReservRemains": {
                                dataValueType: Terrasoft.DataValueType.INTEGER,
                                dependencies: [
                                        {
                                                columns: ["UsrQuantity"],
                                                methodName: "calculateUsrReservRemains"
                                        }
                                ]
                        }
                },
                diff: /**SCHEMA_DIFF*/[
                        {
                                "operation": "insert",
                                "name": "UsrQuantityWorkOrdere",
                                "values": {
                                        "layout": {     "colSpan": 12,"rowSpan": 1,"column": 12,"row": 4,"layoutName": "Header"},
                                        "bindTo": "UsrQuantityWorkOrder"
                                },
                                "parentName": "Header",
                                "propertyName": "items",
                                "index": 4
                        },
                        {
                                "operation": "insert",
                                "name": "UsrQuantity",
                                "values": {
                                        "layout": {"colSpan": 12,"rowSpan": 1,"column": 0,"row": 3,"layoutName": "Header"
                                        },
                                        "bindTo": "UsrQuantity"
                                },
                                "parentName": "Header",
                                "propertyName": "items",
                                "index": 5
                        },
                        {
                                "operation": "insert",
                                "name": "UsrReservRemains",
                                "values": {
                                        "layout": {"colSpan": 12,"rowSpan": 1,"column": 0,"row": 4,"layoutName": "Header"
                                        },
                                        "bindTo": "UsrReservRemains"
                                },
                                "parentName": "Header",
                                "propertyName": "items",
                                "index": 6
                        },
                        {
                                "operation": "insert",
                                "name": "UsrToWorkOrder",
                                "values": {
                                        "layout": {"colSpan": 12,"rowSpan": 1,"column": 12,"row": 3,"layoutName": "Header"
                                        },
                                        "bindTo": "UsrToWorkOrder"
                                },
                                "parentName": "Header",
                                "propertyName": "items",
                                "index": 7
                        }
                ]/**SCHEMA_DIFF*/,
                methods: {
                        calculateUsrReservRemains: function() {
                                if (!this.get("UsrLastQuantity")) {
                                        this.set("UsrLastQuantity", 0);
                                }
                                if (!this.get("UsrReservRemains")) {
                                        this.set("UsrReservRemains", 0);
                                }
                                var result = this.get("UsrReservRemains") + this.get("UsrQuantity") - this.get("UsrLastQuantity");
                               
                                this.set("UsrReservRemains", result);
                                this.set("UsrLastQuantity", this.get("UsrQuantity"));
                        },
                        quantityVlidator: function() {
                                var invalidMessage = "";
                                if (this.get("UsrQuantity") this.get("UsrReservRemains")) {
                                        invalidMessage = this.get("Resources.Strings.ValueOfReservGraterThenQuantity");
                                }
                                return {
                                        fullInvalidMessage: invalidMessage
                                        invalidMessage: invalidMessage
                                };
                        },
                        setValidationConfig: function() {
                                this.callParent(arguments);
                                this.addColumnValidator("UsrQuantity", this.quantityVlidator);
                                this.addColumnValidator("UsrReservRemains", this.quantityVlidator);
                        }
                },
                rules: {}
        };
});

 

Нравится

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

"Сергей Джулай" написал:Буду признателен за подсказку

Скрин консоли с ошибкой приложите, пожалуйста

Да дело в том что ошибки в консоли нету. На странице редактирования заказа деталь с редактируемым реестром(21.jpg), и валидация там не работает (но и ошибок нет). Когда же на странице редактирования самой детали работает все отлично(20.jpg).
А нужна валидация, что бы не открывать новую страницу.

А код немного сменил (Упростил)

quantityVlidator: function() {
    var invalidMessage = "";
        if (this.get("UsrQuantity") < 1) {
            nvalidMessage = this.get("Resources.Strings.ValueOfReservGraterThenQuantity");
        }
    return {
        fullInvalidMessage: invalidMessage,
        invalidMessage: invalidMessage
    };
},
setValidationConfig: function() {
    this.callParent(arguments);
    this.addColumnValidator("UsrQuantity", this.quantityVlidator);
}

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

save: function() {
	if (this.get("UsrString").length === 12) {
		this.callParent(arguments);
	} else {
		this.showInformationDialog("Колонка String должна содержать 12 символов!");
	}
}

Спасибо Максим. Я так и реализовал валидацию, но это слабовато, так как в РР если внести неверное значение, то оно все равно сохранится, хоть и выдаст информационное окно с ошибкой. А это уже риск сломать некую логику. Может можно как то реализовать некую валидацию в момент события сохранения в GRIDе ? Например на событие выделения строки, поля которые должны проверяться сохраняются в временные переменные, а по событию save происходит валидация и если она не проходит, то значения возвращаются с временных переменных.

Посмотрите в сторону ConfigurationGridUtilities, там есть onActiveRowAction, можете переопределить его, и добавить валидацию там. Переопределять этот метод необходимо на схеме детали, и общатся со схемой карточки через sandbox.

Спасибо Максим. За подсказку - буду дальше размышлять в подсказанном направлении.

Сергей,

Поделитесь, пожалуйста, решением данной задачи.

Добрый день Алла. К сожалению до правильной реализации руки так и не дошли. Сейчас проверки выполнена с помощью предупреждения.

attributes: {
	"UsrQuantityWorkOrder": {
		dataValueType: Terrasoft.DataValueType.INTEGER,
		dependencies: [
			{
				columns: ["UsrQuantityWorkOrder"],
				methodName: "validationUsrQuantityWorkOrdere"
			}
		]
	}
},
methods: {
	validationUsrQuantityWorkOrdere: function() {
		if (this.get("UsrQuantityWorkOrder") > this.get("UsrReservRemains")) {
			this.showInformationDialog("Значение больше чем значиние Остаток в резерве");
		}
	}
}

Сергей, спасибо за информацию.

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

Кстати, интересно реализована ли валидация для редактируемого реестра в версии 7.10?

Кто в курсе?

Да, вы правы, пользователь может внести неверное значение, нужно все таки разобраться с sandbox и ConfigurationGridUtilities.

Как собственно и в обычных деталях и карточках - Ваша задача изучить цепочку вызовов функций сохранения (в каждом случае все немного отличается).
Определите подходящий метод в цепочке вызовов (который вызывается на исполнение до непосредственной записи в БД, обладает необходимым контекстом (this) и т.д.), ну и переопределите его - обогатив своей логикой валидации.
Валидация пройдена - "отпускаем" по this.callParent(arguments) [По естественной ветке]
Не пройдена - прерываем выполнение, и всего делов (показываем наши сообщения, открываем справочники - все что душе угодно)
Если в валидации задействованы асинхронные вызовы - например ESQ запросы.
вам вот сюда "Раcширить логику save, после валидации. Контроль Chain выполнения"

Илья,

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

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

Спасибо за то, что поделились опытом!

Советую присмотреться и отладить метод "unSelectRow"
в частности вызываемый им "saveRowChanges" (схема ConfigurationGridUtilities)


Так что замещайте ConfigurationGridUtilities переопределяйте saveRowChanges
Внедряя в нее логику валидации до "row.save"- и будет Вам счастье.

Илья,

спасибо Вам за помощь в поиске подходящего решения :smile:

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

 

В анонсе 7,13 єтого нет (не кидайте в меня тапками если не заметил) Так что ждите или программируйте!

Григорий Чех,

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

Значит или ждать или кастомно делать под себя, (Проверять до сохранения и потом если все ок сохранять )

Григорий Чех пишет:Получается в saveRowChanges изменять условие под себя из ответа Севостьянов Илья Сергеевич?

См. также тут и тут.

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

Добрый день!

Можно ли для мобильного приложения добавить валидацию к полю или, например, ограничение (для даты)?

Нравится

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

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

Уточните, пожалуйста, какую валидацию вы хотите настроить?

"Демьяник Алексей" написал:

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

Уточните, пожалуйста, какую валидацию вы хотите настроить?


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

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

Здравствуйте.
Есть пример реализации в MobileActivityModelConfig. В «Активностях», по умолчанию, не разрешается устанавливать дату начала больше даты завершения активности.

Terrasoft.sdk.Model.addBusinessRule("Activity", {
ruleType: Terrasoft.RuleTypes.Comparison,
triggeredByColumns: ["StartDate"],
leftColumn: "DueDate",
comparisonOperation: Terrasoft.ComparisonTypes.GreaterOrEqual,
rightColumn: "StartDate"
});

Terrasoft.sdk.Model.addBusinessRule("Activity", {
ruleType: Terrasoft.RuleTypes.Comparison,
triggeredByColumns: ["DueDate"],
leftColumn: "StartDate",
comparisonOperation: Terrasoft.ComparisonTypes.LessOrEqual,
rightColumn: "DueDate"
});

Спасибо большое!

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

"Колебянов Виталий Романович" написал:

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

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

"Вильшанский Дмитрий" написал:
Колебянов Виталий Романович пишет:

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

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

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

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

Датой регистрации обращения считается дата создания записи. В случае, если на сервер не будет передаваться дата регистрации, то подставляться будет текущая дата/время.

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

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

Нравится

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

Александр, добрый вечер!

Уточните, пожалуйста, какая у вас бизнес-задача? Какую валидацию вы хотите настроить?

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

Александр, здравствуйте!

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

https://academy.terrasoft.ru/documents/technic-sdk/7-8/biznes-pravila-i…

https://academy.terrasoft.ru/documents/technic-sdk/7-8/pravilo-bindpara…

http://www.community.terrasoft.ru/forum/topic/12990

Виталий Красный,

вы что плохо читаете? вам человек написал, что нужна валидация на ГРИД детали, а не на страницу редактирования. Он же пишет, что валидация для ПОЛЯ не подходит

Демьяник Алексей,

что непонятного, зачем вы переспрашиваете? там же написано на ГРИД детали, значит для детали с реестром. Это тот случай, когда в вашей документации ничего нет по этому поводу. Никакой информации как валидировать детали с реестром нет.

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