При выведенных итогах в менеджере деталей (например на вкладках родительские/подчиненные документы)при переходе по записям в реестре неправильно считаются итоги, а потом вообще менеджер деталей вылетает. Подсчет идет как суммирование по пользовательским полям типа Дробное число. Количество знаков после коммы не 2(как в пользовательском поле), а максимально возможные 15, причем иногда в последнем знаке попадаются цифры, отличные от 0, чего быть тоже не должно(((
Кстати, при изменении точности для Дробного числа с 4 до 2 в датасете в админке, в таблице значение изменить не удается. Если же вернуть точность на стандартные 4 знака после коммы, проблема с итогами не исчезает.
Не могу понять в чем причина:confused:

Нравится

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

"Fishi" написал:при изменении точности для Дробного числа с 4 до 2 в датасете в админке, в таблице значение изменить не удается

Объясните, пожалуйста, подробнее. Вы пытаетесь изменить точность в поле сервиса tbl_*, и не удаётся? Или Вы имели в виду что-то другое?

Попробуйте добиться того, чтобы точность в поле таблицы и в аналогичном поле датасета совпадала. Если не получится сохранить таблицу в базе данных после изменения точности, попробуйте сохранить сервис без обновления структуры БД, а точность в таблице измените средствами СУБД (напр., Enterprise Manager).

Олег Лабьяк,
разработчик,
3-я линия Службы поддержки Terrasoft.

Да, для пользовательского поля точность в датасете и таблице ровна 4. В датасете изменить на 2 можно, а в таблице - нет.

"Лабьяк Олег Игоревич" написал:измените средствами СУБД (напр., Enterprise Manager)

А не подкажете как реализовать в Microsoft SQL Server Management Studio 9.00.3042.00?
Но даже если точность везде ровна 4, при выводе итогов менеджер деталей тоже вылетает.

Выберите нужную таблицу, правой кнопкой мыши вызовите контекстное меню, в нём - пункт Modify. Откроется окно редактирования таблицы, найдите нужное поле и измените его точность (decimal(18, 2)).

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

Олег Лабьяк,
разработчик,
3-я линия Службы поддержки Terrasoft.

Так и делал, изменяю (decimal(18, 4)) на (decimal(18, 2)). Перезапускаю скул, смотрю в админке - в таблице опять точность 4:confused:

upd: кеш чистил)

Вы пересохранили сервис таблицы? Система должна была задать Вам два вопроса: первый касается сохранения сервиса, второй - обновления структуры БД. На первый нужно ответить: "Да", на второй - "Нет".

Олег Лабьяк,
разработчик,
3-я линия Службы поддержки Terrasoft.

Вопрос один:
Следующие таблицы будут изменены в базе данных. Продолжить?
////список таблиц
При сохранении появляется предупреждение о возможности потери данных при преобразовани столбца.
Вот, больше ничего

Это в Management Studio. Я же говорю про сохранение сервиса в Администраторе.

Олег Лабьяк,
разработчик,
3-я линия Службы поддержки Terrasoft.

Конфликт инструкции ALTER TABLE с ограничением FOREIGN KEY "...". Конфликт произошел в базе данных, таблица ...(пользовательское поле типа справочник), колонка ID.
Чем одно поле может мешать изменять другое, совсем с ним не связанное?

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

update tbl_Account
set CityID = NULL
where not exists (select tbl_City.ID from tbl_City
                  where tbl_City.ID = tbl_Account.CityID)

Вместо tbl_Account необходимо подставить название таблицы, которую Вы пытаетесь пересохранить, а вместо tbl_City - название таблицы справочника. Соответственно изменить и названия колонок таблиц.

Олег Лабьяк,
разработчик,
3-я линия Службы поддержки Terrasoft.

Создал нужный запрос(uq_Document). В датасете установил его как запрос на обновление, но результата ноль((
Возможно я что-то делаю не так?

"Лабьяк Олег Игоревич" написал:Если вылетает менеджер деталей, возможно, что-то не так с обработчиком события OnDatasetAfterPositionChange даталинка реестра. Проверьте, пожалуйста.

Изменений не вносил, вот текст:

function dlDocumentsOnDatasetAfterPositionChange(Dataset) {
	if (Dataset.Attributes('IsNew') != true) {
		RefreshDetails();
	}
	Dataset.Attributes('IsNew') = false;
}

Fishi, возможно, я не совсем корректно объяснил. Данный запрос предназначался для удаления некорректных связей со справочником. Его нужно было выполнить один раз в Management Studio, а после этого попытаться сохранить сервис таблицы ещё раз.

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

Олег Лабьяк,
разработчик,
3-я линия Службы поддержки Terrasoft.

"Лабьяк Олег Игоревич" написал:Его нужно было выполнить один раз в Management Studio, а после этого попытаться сохранить сервис таблицы ещё раз.

В результате выполнения получилось:
строк обработано: 0
Запрос успешно выполнен
Но сервис таблицы изменить не удается по той же причине.

По поводу второго вопроса:
При выводе итогов (род/доч документы например) для первых нескольких записей из реестра (раздел Документы) итоги выводятся (но нет округления до 2 или 4 знака, а отображаются 15 цифр после коммы),а потом менеджер деталей стает неактивным(серый фон). Никаких сообщений об ошибке тоже нет.

Думаю, нужен удалённый доступ для анализа проблемы.

Если это возможно, вышлите, пожалуйста, параметры удалённого доступа на support@tscrm.com .

Олег Лабьяк,
разработчик,
3-я линия Службы поддержки Terrasoft.

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

--------------------------------------------
Лабитек
Центр разработки приложений

Исправили в билде 3.2.0.63, запрашивайте у саппорта.
--------------------------------------------
Лабитек
Центр разработки приложений

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

Условие:
Существует два поля Дата начала, Дата окончания и третье поле Количество дней.
Функция подсчёта встроена в след функцию, которая выполняется на пересчёт датасета "Продукт в договоре":

function FillOfferingName(Dataset)
        //вычисление дней между датами курса (продолжительность курса)
        // Первая дата
        var Date1 = new Date(Dataset.ValAsDateTime('DeliveryDate'));
        Date1.setUTCHours(0,0,0,0);
        // Вторая дата
        var Date2 = new Date(Dataset.ValAsDateTime('FinishDate'));
        Date2.setUTCHours(0,0,0,0);
        // Сколько целых дней между датами
        var Year1 = Date1.getYear();
        var Year2 = Date2.getYear();
        if ((Year1>2000) && (Year2>2000)) {
        var Days = Math.floor((Date2.getTime() - Date1.getTime())/(1000*60*60*24));
        Dataset.ValAsInt('CourseDuration') = Days;
        }
        else
        {
    Dataset.ValAsInt('CourseDuration') = 0;
        }

Исполнение пересчёта происходит после повторного открытия окна.

Задача:

Каким образом запустить пересчёт после изменения Даты1 или Даты2, без повторного открытия окна?

Нравится

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

Можно повесить событие на Таймер.
upd/
не посмотрел что на изменения дат.
На событие датасета OnDatasetDataChange, если даты будут изменятся с помощью датасета, а не апдейт запросов или тригеров.

думаю, что нужно сделать на DatasetDataChange, а если будет необходимо изменять даты без помощи датасета, то учесть, что пересчет придется делать дополнительно

Пробовал через OnDatasetDataChange - выдаёт ошибку
"TSObjectLibrary.DBDataset: Не возможно изменить значение вычисляемого поля"

function DataChange(DataField, ScriptObject){
	if (DataField == null) {
		return;	
	}
	var DataFields = DataField.ParentDataFields;
	var Dataset = DataFields.ParentDataset;
	var Value = DataField.Value;
	switch (DataField.Name){
	    case ('DeliveryDate') :
	        //вычисление дней между датами курса (продолжительность курса)
			// Первая дата (год, месяц, день)
			var Date1 = new Date(Dataset.ValAsDateTime('DeliveryDate'));
			Date1.setUTCHours(0,0,0,0);
			// Вторая дата (год, месяц, день)
			var Date2 = new Date(Dataset.ValAsDateTime('FinishDate'));
			Date2.setUTCHours(0,0,0,0);
		  	// Сколько целых дней между датами
		  	var Year1 = Date1.getYear();
		  	var Year2 = Date2.getYear();
			if ((Year1>2000) && (Year2>2000)) {
			var Days = Math.floor((Date2.getTime() - Date1.getTime())/(1000*60*60*24));
			Dataset.ValAsInt('CourseDuration') = Days;
			}
			else
			{
 	   	    Dataset.ValAsInt('CourseDuration') = 0;
			}

Какие вычисляемые поля есть в датасете ?

Я так понимаю это поле CourseDuration. Так его в событии вычисления полей нужно менять.
Upd: наконец-то понял в чем вопрос :) Попробуйте на изменение полей значение не присваивать , а.... получать :) Т.е. взов FillOfferingName с присвоением значения поля CourseDuration переносим в OnCalc. А в OnChange делаем просто

var CourseDuration = Dataset.Values('CourseDuration'); 

Пока что 2 поля: Offering и CourseDuration.
Отладчик ругается на CourseDuration в вышеизложенном коде

Dataset.ValAsDateTime('CourseDuration') = Days;

:) так то оно так. Может проще будет его обычным сделать, а не вычисляемым?

Если я правильно понял, то здесь:

var Days = Math.floor((Date2.getTime() - Date1.getTime())/(1000*60*60*24));

Days - будет целое число
А здесь

Dataset.ValAsDateTime('CourseDuration') = Days;

Вы его в DateTime присваиваете... Сделайте вычисляемое Целое..

--
www.it-sfera.com.ua

"Глова Сергей" написал:Может проще будет его обычным сделать, а не вычисляемым?

уже подумывал над этим...
мне то нужно только отображение количества дней между двумя датами в интерактиве...
Ща попробую вариант Underscore a.k.a. _, если не выйдет сделаю обычным и ручную калькуляцию OnPrepare и OnChange..

---
Конфигурация:
TSCRM 3.3.1.36
Firebird 2.0 (v.2.0.3.12981)

А какая такая калькуляция на OnPrepare ? И обратите внимание на замечание Виталия.

"Виталий Ковалишин aka samael" написал:Вы его в DateTime присваиваете... Сделайте вычисляемое Целое..

Та нет, поле вычисляемое целое, это копипейст враг логики))
поправил в первом коде...

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

"Underscore a.k.a. _" написал:Т.е. взов FillOfferingName с присвоением значения поля CourseDuration переносим в OnCalc. А в OnChange делаем просто

К сожалению не помогло...
Теперь при смене даты она становиться не активной, а вычисляемое поле Offering очищается...
---
Конфигурация:
TSCRM 3.3.1.36
Firebird 2.0 (v.2.0.3.12981)

на datasetdatachange при изменении дат можно вызвать

Dataset.CalcDataFields();

"Раловец Ольга" написал:

К сожалению не работает, так как неопределён датасет в datasetdatachange(datafield), а если получать его по datafield'у
var DataFields = DataField.ParentDataFields;
var Dataset = DataFields.ParentDataset;
то весь запуск TS заканчивается подвисанием и завершением задачи...

---
Конфигурация:
TSCRM 3.3.1.36
Firebird 2.0 (v.2.0.3.12981)

var DataFields = DataField.ParentDataFields;
var Dataset = DataFields.ParentDataset;

Вот именно так и нужно брать датасет, зависание происходит, наверное, по какой-то другой причине.
Вам нужно пересчитывать значение вычисляемого поля только в OnDatasetCalcFields(Dataset) и на datasetdatachange только вызывать CalcDataFields. Возможно, у Вас одно из полей дата пересчитывается при изменении другого и закцикливается, пройдитесь под отладчиком.

"Раловец Ольга" написал:

Нет даты не пересчитываются, но есть ещё одно поле Offering(так как я работаю с "Продуктами в договоре")
Думаю оно и влияет...
Цикл видится так:
в момент присваевания Dataset.Values('Offering') = Offering; во время пересчёта полей по функции

function FillOfferingName(Dataset) {
	var Offering;
	var OfferingID = GetFieldValueFromDisabledField(Dataset, 'OfferingID');
	if (!IsEmptyGUID(OfferingID)) {
		Offering = GetFieldValueFromDisabledField(Dataset, 'OfferingName');
	} else {
		Offering = GetFieldValueFromDisabledField(Dataset, 'CustomOffering');
	}
	debugger;	
	Dataset.Values('Offering') = Offering;
	//вычисление дней между датами курса (продолжительность курса)
	//Первая дата (год, месяц, день)
	var Date1 = new Date(Dataset.ValAsDateTime('DeliveryDate'));
	Date1.setUTCHours(0,0,0,0);
	// Вторая дата (год, месяц, день)
	var Date2 = new Date(Dataset.ValAsDateTime('FinishDate'));
	Date2.setUTCHours(0,0,0,0);
  	// Сколько целых дней между датами
  	var Year1 = Date1.getYear();
  	var Year2 = Date2.getYear();
	if ((Year1>2000) && (Year2>2000)) {
	var Days = Math.floor((Date2.getTime() - Date1.getTime())/(1000*60*60*24));
	Dataset.ValAsInt('CourseDuration') = Days;
	}
	else
	{
    Dataset.ValAsInt('CourseDuration') = 0;
	}
}

меняется значение поля Offering, при этом вызывается ondatasetdatachange в котором, в свою очередь запускается Dataset.CalcDataFields(); Так что при такой реализации не возможно выйти из данного цикла...соответственно способ неверен.

UPD: Та же история повторяется с присвоением CourseDuration.
Само присвоение уже меняет датасет, а изменение датасета запускает пересчёт.

Может есть ещё идеи?

---
Конфигурация:
TSCRM 3.3.1.36
Firebird 2.0 (v.2.0.3.12981)

Так а зачем вызывать Dataset.CalcDataFields() при изменении поля Offering? Его же надо вызывать только при изменении дат?

Если Вы напишете следующим образом

Dataset.DisableEvents();
Dataset.ValAsInt('CourseDuration') = Days;
Dataset.EnableEvents();

то при изменении значения поля CourseDuration событие DataChange вызываться не будет. В datasetdatachange должно быть условие

if ((DataField.Name == 'DeliveryDate') || (DataField.Name == 'FinishDate')) {
   Dataset.CalcDataFields(); 
}

То есть, нужно вызывать CalcDataFields() только на изменение этих двух дат, тогда после изменения поля "Название" внутри FillOfferingName() CalcDataFields() срабатывать не будет.

"Underscore a.k.a. _" написал:Так а зачем вызывать Dataset.CalcDataFields() при изменении поля Offering? Его же надо вызывать только при изменении дат?

Ну да, спасибо, поправил как посоветовала Ольга
"Раловец Ольга" написал:

Спасибо большое, всё заработало.

Upd: правда добавил ещё 2 поля даты('DepartureDate','ReturnDate'), 1 поле исчисляемое('TripDuration')...
Сделал всё как для предидущего случая..

Dataset.DisableEvents();
Dataset.ValAsInt('TripDuration') = Days2;
Dataset.EnableEvents();
if ((DataField.Name == 'DeliveryDate') || (DataField.Name == 'FinishDate') || (DataField.Name == 'DepartureDate') || (DataField.Name == 'ReturnDate')) {
   Dataset.CalcDataFields();
}

Всё считает и показывает...
Но при нажатии на кнопку OK выскакивает сообщение "Не возможно изменить значение вычисляемого поля" для TripDuration в onCalc.

---
Конфигурация:
TSCRM 3.3.1.36
Firebird 2.0 (v.2.0.3.12981)

Добрый день.

Александр, я всё-таки не совсем понимаю, зачем устанавливать значения вычисляемым полям в функции FillOfferingName, тем более, что к названию продукта они никаким образом не относятся. Нельзя всё, что идёт после строки

//вычисление дней между датами курса (продолжительность курса)

перенести в обработчик события OnDatasetCalcFields? Вся эта часть должна нормально отработать и там.

Если так сделать, то будет иметь смысл перед вызовом FillOfferingName в обработчике OnDatasetDataChange вставить проверку

if ((DataField.Name == 'OfferingID') || (DataField.Name == 'CustomOffering')) {
FillOfferingName(Dataset);
}

поскольку только эти два поля влияют на название.

"Лабьяк Олег Игоревич" написал:

Спасибо, за время ковыряния уже перенёс функции вычисления из
FillOfferingName в отдельные RecalcCourseDates и RecalcTripDates. Но от перестановки слагаемых, сумма не меняется...(смайлик пожимает плечами)
OnDataChange:

var DataFields = DataField.ParentDataFields;
var Dataset = DataFields.ParentDataset;
	DataChange(DataField, ds_OfferingInContractScript);
if ((DataField.Name == 'DeliveryDate') || (DataField.Name == 'FinishDate')) {
    RecalcCourseDates(Dataset);
}
if ((DataField.Name == 'DepartureDate') || (DataField.Name == 'ReturnDate')) { 
    RecalcTripDates(Dataset);
}

OnCalc:

function SelfOnDatasetCalcFields(Dataset) {
	FillOfferingName(Dataset);
	RecalcCourseDates(Dataset);
	RecalcTripDates(Dataset);
}

Возможно что то измениться если подскажите как получить DataField в OnDatasetDataChange(Dataset)?

---
Конфигурация:
TSCRM 3.3.1.36
Firebird 2.0 (v.2.0.3.12981)

Александр, насколько я знаю, в OnDatasetDataChange именно DataField и является параметром:

function SelfOnDatasetDataChange(DataField) {...}

В обработчике SelfOnDatasetCalcFields(Dataset) DataField можно получить так:

DataField = Dataset.DataFields.ItemsByName(FieldName);

Попробуйте вместо

if ((DataField.Name == 'DeliveryDate') || (DataField.Name == 'FinishDate')) {
RecalcCourseDates(Dataset);
}

вызывать

if ((DataField.Name == 'DeliveryDate') || (DataField.Name == 'FinishDate')) {
Dataset.CalcDataFields();
}

как писала Оля Раловец. Соответственно и для второго условия.

Олег мы с Вами запутались...

"Лабьяк Олег Игоревич" написал:Если так сделать, то будет иметь смысл перед вызовом FillOfferingName в обработчике OnDatasetDataChange вставить проверку
if ((DataField.Name == 'OfferingID') || (DataField.Name == 'CustomOffering')) {
FillOfferingName(Dataset);
}

Дело в том что FillOfferingName вызывается в OnCalc, a не в OnChange...

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

"Швец Александр" написал:Всё считает и показывает...
Но при нажатии на кнопку OK выскакивает сообщение "Не возможно изменить значение вычисляемого поля" для TripDuration в onCalc.

---
Конфигурация:
TSCRM 3.3.1.36
Firebird 2.0 (v.2.0.3.12981)

Сорри, когда я писал свой пост, я видел только то Ваше сообщение, в котором "выполняется на пересчёт датасета "Продукт в договоре"". Скриптов, которые Вы привели в последнем сообщении, не было.

Я бы сделал так:

function SelfOnDatasetDataChange(DataField) {
var DataFields = DataField.ParentDataFields;
var Dataset = DataFields.ParentDataset;
DataChange(DataField, ds_OfferingInContractScript);
if ((DataField.Name == 'DeliveryDate') || (DataField.Name == 'FinishDate') || (DataField.Name == 'DepartureDate') || (DataField.Name == 'ReturnDate')) {
Dataset.CalcDataFields();
}
}

------------------------------------------

function SelfOnDatasetCalcFields(Dataset) {
FillOfferingName(Dataset);
RecalcCourseDates(Dataset);
RecalcTripDates(Dataset);
}

"Лабьяк Олег Игоревич" написал:

так и сделал...
результат:
TSObjectLibrary.DBDataset: Не возможно изменить значение вычисляемого поля
в

function RecalcTripDates(Dataset) {
	var Date3 = new Date(Dataset.ValAsDateTime('DepartureDate'));
	Date3.setUTCHours(0,0,0,0);
	// Вторая дата (год, месяц, день)
	var Date4 = new Date(Dataset.ValAsDateTime('ReturnDate'));
	Date4.setUTCHours(0,0,0,0);
  	// Сколько целых дней между датами
  	var Year3 = Date3.getYear();
  	var Year4 = Date4.getYear();
	if ((Year3>2000) && (Year4>2000)) {
	var Days2 = Math.floor((Date4.getTime() - Date3.getTime())/(1000*60*60*24));
	Dataset.DisableEvents();
	Dataset.ValAsInt('TripDuration') = Days2;
	Dataset.EnableEvents();
	}
	else
	{
	Dataset.DisableEvents();
    Dataset.ValAsInt('TripDuration') = 0;
    Dataset.EnableEvents();
	}	
}

на строке

Dataset.ValAsInt('TripDuration') = Days2;

UPDATE
Обход данной ошибки реализован заменой вычисляемого поля - обычным Целочисленным.
И переносом функции исчисления второго количества дней из OnCalc в OnChange...
Хотелось бы уточнить у старожилов смысл исчесляемых полей?
Как мне показалось это дубль обычного поля и функции он OnChange...
Поправте меня пожалуйста...

P.S. Ещё раз всем спасибо за помощь и поддержку....

Вычисляемые поля - это данные которые нет надобности или смысла хранить в базе данных. Так как их можно вывести по какой-нибудь формуле.
Например есть поле дедлайн в базе данных. А нужно знать сколько времени осталось до дедлайна - вот в таких случаях очень пригодится вычисляемое поле

"Глова Сергей" написал:

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

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

---
Конфигурация:
TSCRM 3.3.1.36
Firebird 2.0 (v.2.0.3.12981)

Аможет убрать в

    Dataset.DisableEvents();
    Dataset.ValAsInt('TripDuration') = 0;
    Dataset.EnableEvents();

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

Кстати такие вещи нужно в try finally делать.

"Underscore a.k.a. _" написал:Аможет убрать в

В этом случае будут зацикливаться события OnCalc OnChange.
Так как при измении поля TripDuration в OnCalc без отключения событий запускается событие OnChange в котором прописан запуск OnCalc и так до безконечности...

---
Конфигурация:
TSCRM 3.3.1.36
Firebird 2.0 (v.2.0.3.12981)

Так CalcDataFields вызывается по изменению других полей.

"Underscore a.k.a. _" написал:Так CalcDataFields вызывается по изменению других полей.

Да, но в контроле поля на форме результат исчисления показывается только после повторного открытия формы...
До этого - сохраняется старое значение...
---
Конфигурация:
TSCRM 3.3.1.36
Firebird 2.0 (v.2.0.3.12981)

Можно попробовать контрол отвязать от поля и привязать его обратно

"Underscore a.k.a. _" написал:Можно попробовать контрол отвязать от поля и привязать его обратно

Это в смысле
edtTripDuration.DataField='';
edtTripDuration.DataField='TripDuration';

И на какое именно событие этот "бубен" :smile: вешать?

---
Конфигурация:
TSCRM 3.3.1.36
Firebird 2.0 (v.2.0.3.12981)

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

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