Вопрос

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 === "Ежедневно" && concertProgramsCount <= 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 === "Ежедневно" && concertProgramsCount > 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 === "Ежедневно" && concertProgramsCount <= 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 && periodicity === "Ежедневно" && (!this.isAddMode() && 
				response.collection.getCount() > countSettings) || (this.isAddMode() && 
				response.collection.getCount() >= 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 

При переходе по 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

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

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

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

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

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

Здравствуйте! В схеме карточки редактирования заказа в системном методе setValidationConfig() регистрирую метод-валидатор для одного из полей. Внутри этого метода делаю запрос к таблице заказов с помощью EntitySchemaQuery и провожу проверку на корректность данных. Как известно, запрос на выборку данных запускается с помощью метода EntitySchemaQuery.getEntityCollection(function(result) { ... }). По-видимому, данный метод работает асинхронно, поэтому метод-валидатор заканчивает свою работу, не дожидаясь результата выборки. В итоге, валидация всегда получается успешной вне зависимости от результата проверки.

Как можно решить эту проблему? Есть ли способ выполнить выборку из базы синхронно?

У меня такой же вопрос

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

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

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

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

подскажите пожалуйста вам Валидацию когда требуется производить в момент заполнения формы или перед сохранением? если к примеру требуется сделать перед сохранением, то ваша задача решаема. За это отвечает метод  asyncValidate . Если у вас конфигурация Sales, пример можно подсмотреть в схеме  ContractPageV2 , там как раз перед сохранением идет проверка Уникальности номера, при проверке выполняется запрос к Базе данных.

для сведения на клиентской стороне все SQL запросы выполняются Асинхронно. И это правильно. Это увеличивает производительность программы. Плюс чтобы вы понимали на клиентской стороне должны быть построены самые элементарные запросы. Если запрос нетривиальный, его требуется строить и выполнять уже на стороне сервера, т.е писать код на C#.

будут вопросы с радостью на них отвечу

Вот код функции, отвечающей за валидацию (упрощенный пример):

actNumberValidator: function() {	
	var invalidMessage = "";
 
	// Получаем список заказов
	var orderEsq = Ext.create("Terrasoft.EntitySchemaQuery", {
		rootSchemaName: "Order",
		isDistinct: true
	});
	orderEsq.addColumn("Number");
	orderEsq.addColumn("UsrActNumber", "ActNumber");
 
	orderEsq.getEntityCollection(function(result) {
		var orderCollection = result.collection.collection;
		var isActNumberExists = orderCollection.items.some(function(item) {
			return item.get("ActNumber") === this.get("UsrActNumber");
		}, this);
 
		if (isActNumberExists) {
			invalidMessage = "Заказ с таким номером акта уже существует";
 
			return {
				invalidMessage: invalidMessage, 
				fullInvalidMessage: invalidMessage
			};
		}
	}, this);
 
	return {
		invalidMessage: invalidMessage,
		fullInvalidMessage: invalidMessage
	};
}

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

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

какой минус я вижу сразу в вашем запросе. Это вы делаете запрос к БД и получаете весь список Заказов, и далее перебираете их и сравниваете их. А если в БД будет Миллион записей? то все клиент ваш подвиснет навсегда или надолго. Давайте идти по порядку. Опишите задачу, какое поле проверяем (при Валидации) какой правильно должен отрабатываться запрос к БД и цель этого запроса. и далее я вам помогу составить и запрос и приведу как этот запрос Асинхронный будет работать при валидации полей. И еще пока незабыл данная валидация когда должна работать при Заполнение полей или при сохранение карточки редактирования. Спасибо!!!

Опишу задачу. Для каждого заказа заполняется поле [Номер акта]. Нумерация актов идет отдельно для каждого контрагента, указанного в прикрепленном к заказу договоре в поле [Наша компания]. Соответственно, в контрагенте есть поле [Номер последнего заказа]. При добавлении нового заказа с указанным договором (поле [UsrContract]) запускается процесс для увеличения номера последнего заказа. Поля [Номер акта] и [Номер последнего акта] должны быль редактируемы. Поэтому при заполнении номера акта необходимо проверять его уникальность.
Может быть, предложите другое, более оптимальное решение данной задачи?

"Дмитрий Д." написал:Нумерация актов идет отдельно для каждого контрагента, указанного в прикрепленном к заказу договоре в поле [Наша компания].

Вопрос где хранится данный номер Акта? в отдельной таблице или где? так как по умолчанию в конфигурации Sales Актов выполненных работ нет. Данная сущность создана с нуля? это отдельный раздел и таблица? если так то как Акт и договор связаны, какой связью "1 ко многим"? Далее вопросы как Заказ связан с Актом выполненных работ и для чего это сделано? я просто немного не понял как у вас сейчас это все Дмитрий реализовано. Поясните поподробнее пожалуйста. Я скажу вам свое мнение правильно или нет. И как бы я реализовал. Так как данную задачу в своей конфигурации я уже выполнил. спасибо!!!

Отдельной сущности Акт нет. Акт распечатывается на объекте Заказ и содержит в шапке примерно такой текст: "Акт №<номер_акта> от <дата_окончания_отчетного_периода> выполненных работ и оказанных услуг к Приложению №<номер_приложения> договора №<номер_договора> от <дата_подписания_договора>". Номер акта хранится в кастомном поле Order.UsrActNumber. Сейчас это поле заполняется руками. Нужно, чтобы это поле заполнялось автоматически. Для этого у контрагента было заведено поле Account.UsrActLastNumber для хранения номера последнего акта. При добавлении нового заказа данное поле инкрементируется и заносится в Order.UsrActNumber.

Хорошо Дмитрий если развивать вашу идею, то вам достаточно при сохранение заказа обновлять поле "UsrActLastNumber" в Контрагентах, а при создании (именно при создании) нового Заказа и при выборе Контрагента из БД заполнять поле "UsrActNumber" + 1 и все. Цель Валидации я просто тогда далее не вижу. Или я чего-то не понял. Поясните пожалуйста еще раз спрашиваю Дмитрий для какого поля вы желаете проводить валидацию и в какой момент в момент Заполнения или в момент Сохранения. Спасибо!!!

Поле UsrActNumber доступно для редактирования. При редактировании этого поля хотелось бы проверить его значение на уникальность.

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

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

Михаил, давайте подойдем к вопросу с другой стороны. Расскажите, как это реализовано у вас? Как вы работаете с актами?

Дмитрий я к данному вопросу подошел следующим образом. Я разделил сущности Договор на 2 части, хозрасчетные договора, данные договора закрываются реализациями и счет-фактурами. И договоры об оказании услуг, вот данные договора закрываются Актами выполненных работ. все разделено на отдельные сущности. У каждой сущности своя нумерация, свои отчетные документы, свои бизнес-процессы. Это маленькое начало большого айсберка :) А в целом полностью закрыл Складской учет, работа с поставщиками, работа с покупателями, управление денежными потоками. Получилось очень даже неплохо. Вот по какому пути я пошел изначально.

Михаил, насколько я понял, у вас Счет-фактура и Акты являются отдельными сущностями, которые отображаются наряду с такими разделами, как заказы и счета? Есть ли в этом смысл, когда для акта необходимо хранить только лишь его номер?

"Дмитрий Д." написал:Михаил, насколько я понял, у вас Счет-фактура и Акты являются отдельными сущностями, которые отображаются наряду с такими разделами, как заказы и счета?

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

да все верно Дмитрий вы поняли. Но смысл есть всегда, во первых данные сущности хранятся отдельно чтобы для данной сущности были свои Отчетные формы, свои бизнес-процессы. Так как BPMOnline изначально создавалась и позиционирует себя как система BPMN позволяющая пользователю помощь в работе и недопустить ошибок и увеличить его производительность. Это первая цель. Вторая цель выгрузка результативных документов из BPMOnline в 1С. Так как бухгалтерия работает в 1С. Пока в BPMOnline бухгалтерия не работает. Но и над этим вопросом я сейчас занимаюсь. Я не пытаюсь скопировать и клонировать 1С. Я сейчас проектирую и разрабатываю систему, на платформе BPMOnline которая закроет все вопросы. Но будет гораздо удобнее, быстрее и т.д. Вот моя цель и задача на сегодня.

Войдите или зарегистрируйтесь, чтобы комментировать
Публикация

В SDK bpm'online в подраздел "Примеры решения типовых задач" добавлены решения кейсов, связанных с разработкой пользовательского интерфейса и бизнес-логики приложения.
Заходите на сайт Terrasoft Academy в раздел "Документация SDK" и узнайте как:

Статьи расположены в разделе "Примеры решения типовых задач"

Поделиться

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

А что за функция asyncValidate в InvoicePageV2? Это какой-то другой способ валидации?

Войдите или зарегистрируйтесь, чтобы комментировать