Не записываются данные в запись после расчета

Добрый день!

У датасета реестра детали есть обработчик:

function ds_DocumentInstallmentGraphOnDatasetCalcFields(Dataset) {

        ...

        tmp_sum[i+1] = tmp_sum[i] + Dataset.ValAsFloat('SquareMeterPaidAmount');
        Dataset.Values('SquareMeterTotalPaidAmount') = tmp_sum[i+1];
        i++;    
}

на форме значения поля SquareMeterTotalPaidAmount меняются, все ок, а в БД не записываются, подскажите, пожалуйста причину.

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

И еще вопрос - как программно обновить реестр? (кнопочка с зелеными стрелочками).

Спасибо заранее!

Нравится

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

Если поле обычное хранящееся в БД, его лучше пересчитывать на событии DataChange при изменении поля, от которого зависит расчёт. Например, так сделано в ds_ContractScript.

По второму вопросу - вызвать RefreshDataset(Dataset).

не помогло:

	if (Name == 'StandartPaymentAmount') {
	 DataFields.ItemsByName('SquareMeterTotalPaidAmount').Value = tmp_sum[i+1];
	}

мне кажется, что я что-то не до конца понимаю.

Если в DataChange - то он даже не пересчитывает при изменении данных. И не меняется визуально ничего в реестре.

А если оставить как у меня в DatasetCalcFields - то все считает/ пересчитывает, а данные не обновляет.

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

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

Может, это поле затирает триггер на таблице?

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

А может кто-нибудь подсказать последовательность событий при работе с реестром? Может дело в том, что обработчик onCalc идет до открытия Dataset или что-нибудь подобное...

Алексей, обработчик события OnDatasetCalcFields предназначен для расчета значений вычисляемых полей (SDK).
В Вашем случае (если поле не вычисляемое) не следует его использовать.

Может, это поле подтягивается из другой таблицы? Проверьте в Select Query этого датасета.

"Соляник Алексей" написал:Если в DataChange - то он даже не пересчитывает при изменении данных. И не меняется визуально ничего в реестре.

А какие данные Вы меняете? в ДатаЧендж-е Вы указываете изменение Вашего поля именно при смене тех данных, которые меняете? т.е., если Вы изменяете поле1, а пересчитать нужно поле2, то код должен быть такой:

if (DataField.Name=='поле1') {
  Dataset('поле2') = //Ваш код пересчета.
}

И да, если не менять тех полей, которые указаны в этой функции, то пересчета не будет.
Если Вам нужно менять его, допустим, при открытии карточки -- то напишите код в функции OnPrepare(), если же перед сохранением -- в фукнции OnBeforePost() или бтнОкОнКлик().

"Соляник Алексей" написал:И не меняется визуально ничего в реестре.

Стоп, а реестр тут причем? Или Вы сделали его редактируемым и ставите галочку в реестре, а не в карточке? Тогда нужно писать пересчет не в скрипте к карточке окна (scr_AccountEditScript), а на самом датасете (scr_AccountScript)...

Ольга, я пишу именно на самом датасете, т.к. карточка тут не причем.

А менять мне надо так:

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

Вот так...

договор -- Договор1
Оплаты -- оплата 1: дата 1, сумма 1, сумма за пред.месяцы 1 (=сумма 1)
оплата 2: дата 2 (дата 2 больше даты 1), сумма 2, сумма за пред.месяцы 2 (=сумма 1+ сумма 2)
...
Схема такая?
т.е. в оплате 1 не нужно учитывать сумму в оплате 2?
и Вы сделали (или хотите сделать) кнопку "обновить", которая ищет все "предыдущие" оплаты, суммирует их и записывает в поле это поле?

А почему бы не сделать это триггером?

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

Ольга, деталь договора:

Месяц                 Оплата за месяц            Всего на дату
___________________________________________________________________
Февраль         500 р.                             500 р.
Март            500 р.                             1000р.
Апрель          500 р.                             1500р.

Всего на дату должно и считать и записывать в БД.

Далее, я нажимаю "изменить" и после изменения Оплата за месяц должны сразу меняться все значения поля Всего на дату.

Диалог изменить/ добавить стандартный диалог GridArea.

Алексей, вижу 2 варианта:
1) колонка-подзапрос
2) кнопка "пересчитать" в реестре.
В первом случае значение все время "пересчитывается", т.е. само "вытягивается" на основании данных. Во втором -- нужно нажать кнопку, чтобы пересчитать, но зато данные постоянно хранятся в бд.

Опишу оба варианта, если нужно будет подробней -- спрашивайте.
1 вариант.
Вам нужно в запрос детали добавить колонку-подзапрос с примерно такой схемой:

select sum(PD.Amount)
from tbl_PaymentsDetail as PD
Where 
PD.ContractID = tbl_PaymentsDetail.ContractID 
AND PD.PeriodID <= tbl_PaymentsDetail.PeriodID

tbl_PaymentDetail -- это Ваша таблица Оплаты
первый фильтр -- по контрактуИД (т.е. чтобы считало по одному и тому же договору)
второй -- по периоду (вот тут могут быть сложности, потому что я не уверена, что так можно сравнивать. скорее всего, придется сравнивать сроки действия периодов из самого справочника Периоды)
сумма -- это в свойствах колонки Amount (оплата за месяц) указать "итоговое значение" = "сумма"

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

2 вариант. кнопка
Есть просто масса вариаций. но приведу самую простую, чтобы понятней было.
Но тут тоже нужно разобраться, как сортировать период. Потому что нужно в запрос детали добавить фильтр сравнения PeriodID:

 tbl_PaymentsDetail.PeriodID<=:PeriodID

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

код на кнопке примерно такой:

var SelectedIDs = grdData.SelectedIDs;
if (!SelectedIDs.Count){
  return;
}
var ContractID = GetDatasetFieldValueByID('ds_PaymentDetail',SelectedIDs([0]),'ContractID');
var PaymentDS =GetSingleItemByCode('ds_PaymentDetail','RecalcAmounts');
PaymentDS.DisableEvents();
var CurrentDataset = dlData.Dataset;
for (var i=0; i<SelectedIDs.Count; i++) {
  PaymentDS .Close();
  ApplyDatasetFilter(PaymentDS,'ContractID',ContractID,true);
  var PeriodID= GetDatasetFieldValueByID('ds_PaymentDetail',SelectedIDs([i]),'PeriodID');
  ApplyDatasetFilter(PaymentDS,'PeriodID',PeriodID,true);
  PaymentDS .Open();
  var Sum = 0;
  PaymentDS .GotoFirst();
  while (!PaymentDS .IsEOF){
    Sum = PaymentDS('Amount');
    PaymentDS .GotoNext();
  }
  if (CurrentDataset.Locate('ID', SelectedIDs([i]))) {
    CurrentDataset.Edit();
    CurrentDataset('TotalAmoun') = Sum;
    CurrentDataset.Post();
  }
}
PaymentDS.EnableEvents();

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

Т.е. в общем схема одна -- для каждой записи нужно посчитать сумму предыдущих записей, где период меньше или равен периоду текущей записи.
Надеюсь, мои мысли натолкнут Вас на правильное решение:smile:
Удачи Вам в реализации!

Спасибо! Второй вариант действительно натолкнул на мысли, посмотрим что получится ;)

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