Добрый день!
У датасета реестра детали есть обработчик:
...
tmp_sum[i+1] = tmp_sum[i] + Dataset.ValAsFloat('SquareMeterPaidAmount');
Dataset.Values('SquareMeterTotalPaidAmount') = tmp_sum[i+1];
i++;
}
на форме значения поля SquareMeterTotalPaidAmount меняются, все ок, а в БД не записываются, подскажите, пожалуйста причину.
Мне просто надо чтобы данные вычислялись на лету и сохранялись в это поле.
Поле в таблице есть, в запросе есть, в датасете есть. Везде одинаковый тип дробный.
И еще вопрос - как программно обновить реестр? (кнопочка с зелеными стрелочками).
Спасибо заранее!
Нравится
Если поле обычное хранящееся в БД, его лучше пересчитывать на событии 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:
Удачи Вам в реализации!
Спасибо! Второй вариант действительно натолкнул на мысли, посмотрим что получится ;)