adding and updating.
DataGrid
Dataset
Скрипты
Разработка

Добрый день

В окне есть DataGrid, привязанный к набору данных A. Под DataGrid'ом есть WindowContainer внутри которого есть DataGrid привязанный к набору данных B.
Набор данных B основан на мудрёном запросе на выборку, основанном на приличном количестве таблиц.

Прошу пояснить как осуществляется процесс добавления записи из набора A в набор B и отобразить сие действо в DataGrid'е окна контейнера.

Делаю следующие шаги.
1. Беру запись из набора A
2. Беру набор B (

var B = Services.GetNewItemByUSI('B');
)
3. Определяю поля и значения
var Fields = new Array(...);
var Values = new Array(...);

4. Использую
AppendRecordInDataset(B, Fields, Values, true);

Прошу помощи в понимании данного процесса.

1. Добавление из A в B.
2. Обновление DataGrid для отображения того что добавили.

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

Нравится

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

Как я полагаю, надо слать Notify. Вопрос чему - Окну (и там проводить обработку) или Набору данных?

Если есть наборы данных А и В, привязанные через DatasetLink к соответствующим гридам и необходимо скопировать выделенную запись из А в В, то нужно:
var Fields = new Array(имена полей, которые копируем);
var Values = new Array(значение из набора данных А (например, А('Поле1') и т.д.));
AppendRecordInDataset(B, Fields, Values, true);
B.RefreshRecord(B('ID'), true);

Если наборы данных находятся в разных окнах, то надо слать Notify окну, в котором В, а в качестве данных передать набор данных А. Функии копирования поместить в обработку OnNotify окна с В.

Показать все комментарии
Скрипты
Разработка

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

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

К примеру есть связка Продажы-Счета. Нужно в зависимости от Состояния оплаты Счета (Оплачен), просуммировать все счета Продажи и занести полученное значение в Продажу (колонка СуммаОплаченныхСчетов).

Создал функцию, которая считает сумму счетов по продаже и пишет в Продажу в колонку AmountPaid полученную сумму:

 var Dataset = dlData.Dataset;
       Dataset.Open();
 ...
SumAmount = SumAmount + Amount;
}
  if (SumAmount!=Dataset.Values('AmountPaid')){
              Dataset.Edit();
              Dataset.Values('AmountPaid') = SumAmount;
              Dataset.Post();
              Dataset.Close();
              }
              InvoiceDataset.Close();

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

Нравится

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

Я считаю, что правильно было бы вообще реализовать это уже в запросе, а не в датасете.
Скрины в приложении (по пунктам)

0) (Опасно, сделайте бекапы) Удалить все, что связано с этим полем (все скрипты с ним, удалить из карточки, грида, датасета, запроса, таблицы)
Или просто будем работать с другим именем поля. Например, PaidAmount.

1) Зайти в sq_Opportunities, добавить колонку подзапроса

2) Меняем имя колонки на нужное нам AmountPaid

3) В подзапросе выбираем таблицу tbl_invoice, называем ее как InvoicePaid

4) В select в подзапросе выбираем Amount или BasicAMount (смотря, что по душе. Я взял BasicAmount) и говорим, что нам нужна его сумма (ставим в поле итог Сумма)

5) Необходимо наложить фильтры
5.1) Фильтр связи продажи с счетом
В подзапросе в Where создать фильтр сравнения, назовем InvoicePaidOpportunityID
Слева в фильтре InvoicePaid.OpportunityID, справа Opportunity.ID
Включить его (не забыть поставить галочку)
5.2) Счета должны быть оплачены
В подзапросе присоединиям таблицу BillStatusID к таблице InvoicePaid
Назовем ее InvoicePaidBillStatus (Остальные параметры смотри на скриншоте 5_2_1)
В подзапросе в Where создать пользовательский SQL фильтр, назвать InvoicePaidBillStatusIsFinish, внизу объеденить с таблицей tbl_BillStatus AS InvociePaidBillStatus, в самом запросе написать 'InvoicePaidBillStatus.IsFinish = 1', не забыть включить фильтр

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

"Сазанов Александр Владимирович" написал:Я считаю, что правильно было бы вообще реализовать это уже в запросе, а не в датасете.
Скрины в приложении (по пунктам)

А не будет ли это очень долго считаться, когда колонка будет отображаться в grid'e?

Спасибо Александр! Работает! Ещё бы где-то рефреш добавить, чтобы в гриде сразу видно было обновление, а не после нажатия на кнопку обновить.
И ещё, где мы наш псевдомин в запросе AmountPaid привязываем к реальному столбцу в таблице?

Если делаете в конфигурации, то лучше всего создать специальный UpdateQuery сервис, который будет выполнять апдейт таблицы "Продажи" (в вашем случае), а затем выполнить его:

var myUQ = Services.GetNewItemByUSI('uq_UpdateOpportunitySumm');
SetParameterValue(myUQ.Parameters, 'OpportunityID', OpportunityID);
SetPArameterValue(myUQ.Parameters, 'OpportunitySumm', Summ);
myUQ.Execute();

Также перед этим, рекомендую еще и написать отдельный SelectQuery, который будет получать сумму по всем счетам продажи (чтобы не работать с датасетом, избежать циклов while и пр., иначе в будущем столкнотесь с проблемой быстродействия). Т.е. в SQ добавить одну колонку с агрегирующей функцией суммы по нужной колонке, и с фильтром сравнения по OpportunityID.

var mySQ = Services.GetNewItemByUSI('sq_GetInvoiceSumm');
SetParameterValue(mySQ.Parameters, 'OpportunityID', OpportunityID);
var DS = sq.Open();
var InvoiceSumm = DS('InvoiceSumm');
DS.Close();

"Владимир Соколов" написал:

А не будет ли это очень долго считаться, когда колонка будет отображаться в grid'e?


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

"Alex GF" написал:

Спасибо Александр! Работает! Ещё бы где-то рефреш добавить, чтобы в гриде сразу видно было обновление, а не после нажатия на кнопку обновить.

И ещё, где мы наш псевдомин в запросе AmountPaid привязываем к реальному столбцу в таблице?


В том-то и дело, что в таблице его нет, он вычисляется в запросе, поэтому не нужно никуда вешать никакие скрипты для его вычисления. А то пришлось бы вешать скрипты на Счета на AfterPost и BeforeDelete или AfterDelete

Показать все комментарии
Word
отчеты
Интеграция и импорт данных
Разработка

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

Нравится

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

Вордовские отчёты практически любой сложности можно построить чисто программно, управляя COM-объектом Word. В своё время для 3.Х были библиотеки (вроде бы даже и не одна) для автоматической замены в бланке документа макросов нужного вида на значения из БД или табличные части отчёта.

Сходу поиском нашёл такое, может быть полезным.

"Рыжаков Олег Евгеньевич" написал:Вопрос в том, как сделать экспорт этих строк в отчет в Word'е, чтобы там формировалась табличка с нужным количеством строк.
Олег, эта базовая логика отображения подчиненной детали в пользовательском отчете MS Word. 
"Рыжаков Олег Евгеньевич" написал:Второй вариант экспорта - каждая строчка в продуктах должна формировать абзац текста. Сколько строк, столько абзацев.
Проиллюстрируйте задачу, так как из описания не совсем понятно.

Показать все комментарии
доступ объекты sql
Технические вопросы
Разработка

Уважаемые коллеги!
Прошу подсказать решение, так как техническая поддержка на сайте игнорирует..
Возникла задача:
BPM Online Realty
Версия 5.4.1.836

средствами субд(ms sql) нужно назначить права на доступ к объектам.
Разобрались, что работать нужно с таблицей объекта типа NAMERights.
Вопросы по самой таблице.
Получается, если например добавлять права на обращения (таблица case) по этой таблице:
должно быть включено администрирование по записям и запись в sql с настройками доступа нужно создавать в таблицу dbo.SysCaseRight, где в поле recordId указывается ИД записи, на которую нужно настроить доступ, а вот с остальными полями не очень понятно:
Operation, RightLevel, Position и SourceID - откуда брать данные для их заполнения и каково их назначение?
Также интересует вопрос - если из этой таблицы средствами sql удалять ненужные записи не возникнет ли ошибок и есть ли связанные таблицы, в которых также нужны будут какие-либо действия?
Заранее спасибо!

Нравится

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

Operation:

0 либо 1 либо 2 - чтение, изменение, удаление соответственно.

RightLevel:

0 - запрет, 1 - разрешение, 2 - разрешение с правами делегирования прав

Position:
номер по порядку;

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


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

ошибок не возникнет. связанных таблиц нет. просто пользователю не отрисуются те записи, на которые у него нет прав на чтение (если объект администрируется по записям, разумеется).

Дмитрий, благодарю за такой развернутый и содержательный ответ! то что нужно :)

Показать все комментарии
Скрипты
Разработка

Здравствуйте!
В Продаже в контекстном меню выполняю «Создать счет». Окно «Счет» висит секунд 30 (не отвечает), затем отвисает.
Тоже самое, если из Продаж создать Договор.

Дебаггером дохожу до функции

function RefreshDataset(Dataset) {
       CheckAssigned(Dataset, 'Dataset');
       Dataset.Close();
       Dataset.Open(); // Здесь 30 секунд висим
}

Профайлер показывает, что на Dataset.Open(); выполняется Select sq_Opportunity за 3 секунды.
И далее в течение 30 секунд висим и затем в профайлере Select Opportunity ID ….
После этого окно Счет отвисает.

Как можно проанализировать, что происходит в Dataset.Open();, чтобы понять причину зависания?
И в чем может быть причина?

Нравится

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

Есть еще события OnDatasetBeforeOpen(Dataset), и OnDatasetAfterOpen(Dataset) - скорее всего там накручена какая-то логика, которая выполняется слишком долго. Установите в этих событиях отладчик, либо на строке Dataset.Open() нажмите F11 (зайти внутрь) чтобы понять что происходит в фоне.

Установил на эти события (wnd_InvoiceEditScript) отладчик, а также на строке Dataset.Open() нажимал F11.
Дальше строки Dataset.Open() не проходит. Сразу после Dataset.Open() выходим на окно Счет, где висим секунд 30, затем отвисаем. Что ещё может быть?

Alex, посмотрите профайлером какой запрос идет в БД и выполните его в Management Studio.
Как долго выполняется запрос?

"Бондарь Наталия" написал:Alex, посмотрите профайлером какой запрос идет в БД и выполните его в Management Studio.
Как долго выполняется запрос?

В заглавном сообщение писал про Профайлер:

"Профайлер показывает, что на Dataset.Open(); выполняется Select sq_Opportunity за 3 секунды.
И далее в течение 30 секунд висим и затем в профайлере Select Opportunity ID …."
В Management Studio он также выполняется за 3 сек.

Также отладчик ставил на ds_Opportunity (OnDatasetBeforeOpen(Dataset), и OnDatasetAfterOpen(Dataset)). (Пробовал ставить отладчик на все функции в ds_OpportunityScript, но не в одну из функций не заходит).

После 30 секундного зависания переходит на ds_OpportunityOnDatasetAfterOpen.

Что происходит в эти 30 секунд скрыто в Dataset.Open() куда не получается войти.

Сам метод Open() не тяжелый. Чтобы проверить, что происходит в методе, необходимо отлаживать исходники приложения, что по понятным причинам Вы сделать не сможете.

"Alex GF" написал:(Пробовал ставить отладчик на все функции в ds_OpportunityScript, но не в одну из функций не заходит)

Вот это самое странное, в базовой реализации обработка присутствует и, если Вы отлаживаетесь в студии, то по F11 должны были попасть на стандартный AfterOpen.
Проверьте наличие подписки на события в ds_Opportunity. Если с этим все в порядке, то останется только передать в поддержку обезличенную копию БД для анализа.

"Maxim Gritsenko" написал:
Проверьте наличие подписки на события в ds_Opportunity. Если с этим все в порядке, то останется только передать в поддержку обезличенную копию БД для анализа.

Удалось ли что-нибудь выяснить по поводу зависания? Обезличенная БД в начале сентября была передана в техподдержку.

Алекс, на предоставленной Вами базе запрос к таблице продаж выполняется 20 секунд из студии.

Максим, скажите пожалуйста, какой именно запрос Вы запускали в Студии?
У меня на рабочей базе (там где виснет 30 сек при создании Счета или Договора) запрос sq_Opportunity в Студии выполняется за 2 сек.
Сами продажи в модуле Продажи работают без зависания.

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

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

Получили ответ от коллег из департамента разработки, для решения данного вопроса, необходимо в сервисе wnd_InvoiceEditScript, в функции Initialize заменить:

if (IsAppend) {
                               var OpportunityID = Dataset.Values('OpportunityID');
                               if (OpportunityID) {
                                               var LookupDataset =
                                                               Dataset.DataFields('OpportunityID').LookupDataset;
                                               RefreshDataset(LookupDataset);
                                               LookupDataset.Locate('ID', OpportunityID);
                                               Dataset.Values('OpportunityID') = OpportunityID;
                               }
                }
На
                if (IsAppend) {
                               var OpportunityID = Dataset.Values('OpportunityID');
                               if (OpportunityID) {
                                               var LookupDataset =
                                                               Dataset.DataFields('OpportunityID').LookupDataset;
                                               ApplyDatasetIDFilter(LookupDataset, OpportunityID, true);
                                               RefreshDataset(LookupDataset);
                                               ApplyDatasetIDFilter(LookupDataset, null, false);
                                               Dataset.Values('OpportunityID') = OpportunityID;
                               }
                }

Спасибо, помогло!

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

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

Нравится

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

Здравствуйте, Николь.

Не совсем понятно, как Вы фиксируете сделки и их результат. Уточните, пожалуйста, этот момент. Какой это раздел, какого типа записи?
Также, необходимо понимать, какой тип отчета Вы хотите использовать? Excel? FastReport?

Продажа должна быть в состоянии Закрыта, у которой заполнено поле Победитель. И продукт, на закладки Продажи, должен быть в позиции Отменено = Ложь.

SELECT
	[tbl_Offering].[Name] AS [Name],
	[tbl_OfferingInOpportunity].[Quantity] AS [Quantity],
	[tbl_OfferingInOpportunity].[IsCanceled] AS [IsCanceled],
	[tbl_Opportunity].[WinnerID] AS [WinnerID],
	[tbl_Opportunity].[Title] AS [Title],
	[tbl_Account].[Name] AS [NameAccount]
FROM
	[dbo].[tbl_OfferingInOpportunity] AS [tbl_OfferingInOpportunity]
LEFT OUTER JOIN
	[dbo].[tbl_Offering] AS [tbl_Offering] ON [tbl_Offering].[ID] = [tbl_OfferingInOpportunity].[OfferingID]
RIGHT OUTER JOIN
	[dbo].[tbl_Opportunity] AS [tbl_Opportunity] ON [tbl_Opportunity].[ID] = [tbl_OfferingInOpportunity].[OpportunityID]
INNER JOIN
	[dbo].[tbl_Account] AS [tbl_Account] ON [tbl_Account].[ID] = [tbl_Opportunity].[WinnerID]
WHERE([tbl_OfferingInOpportunity].[IsCanceled] = :TrueValue AND
	NOT [tbl_Opportunity].[WinnerID] IS NULL)
ORDER BY
	3 ASC,
	1 ASC

Это мой запрос.
Можно ли сделать такой фильтр, чтобы сортировка шла уже в самом запрос?

Здравствуйте, Николь.

Не совсем понятно, как Вы фиксируете сделки и их результат. Уточните, пожалуйста, этот момент. Какой это раздел, какого типа записи?
Также, необходимо понимать, какой тип отчета Вы хотите использовать? Excel? FastReport?

Добрый день.
Хочу попробовать сделать это в FastReport. Результат сделки фиксируется в самой Продаже. Или это не то?

Николь, сложно понять Вашу бизнес-задачу. Скриншот в первом сообщении дате представление об одном, запрос - о другом.
Предлагаю к ознакомлению пример небольшого отчета, который выводит список продуктов и количество побед по продажам Вашей компании и других компаний. Прикрепил сервисы.
sq_nikolreport.rar

Добры день.
Я правильно понимаю, что количество побед - это заполненное в продаже поле Победитель?
И еще вопрос. Менеджеры нашей компании в поле победитель, при победе нашей компании, пишут либо Ваша компания, либо ООО АСТ... Можно ли как-то добавить второй UID в параметр?

Количество побед - это количество продуктов в продажах с заполненным победителем, да.
Можно в sq добавить группу фильтров объединенную логическим ИЛИ и добавить два фильтра сравнения с одним и со вторым идентификатором.

Показать все комментарии
Excel Импорт
excel отчет
импорт
интеграция
отчет
Интеграция и импорт данных
Разработка

Добрый день! При импорте отчета в excell числовое значение поля (19 символов) отображается некорректно (1 во вложении). При попытке поменять формат ячейки в готовом отчете число отображается полностью, но снова некорректно (последние цифры числа - нули, а должны быть отличными от нуля) 2. во вложении. Помогите исправить эту ошибку=(

Нравится

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

Здравствуйте, Олеся.

Номер договора - это текстовое поле. В Excel Вы, скорее всего, переводили формат колонки в числовой (Number). Но максимальное значение, которое может хранить этот тип данных - 2 147 483 647. Переводите в текст.

Здравствуйте, Максим! Если переводить формат ячейки в текст, то поле остается некорректным, 3,163E+17=(

Грубо говоря, значение ячейки импортируется неверно, 316300027614000000, нули вместо последних цифр, по-умолчанию.

Олеся, а уточните, пожалуйста версию и сборку, которую используете.

Максим, Версия: 3.3.2.252

Олеся, воспроизвел ситуацию на коробочной версии. Вероятно, при подготовке Excel файла не учитывается формат колонки в наборе данных. В версии 3.4.1 этого уже нет, постараюсь спустить необходимый функционал, если не удастся, зарегистрируем обращение в департамент разработки.

Спасибо, Максим, очень жду!

Показать все комментарии
Установка и Администрирование
Разработка

Добрый день!
Проблема:
Завел нового пользователя домена, конкурентные лицензии.
Теперь никто зайти в террасофт не может (Лицензия для модуля ... не найдена).
Нужно ли пере заказывать файл лицензии? В чем проблема

Нравится

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

Вопрос закрыт. Контрагента указал не того!

С конкурентными лицензиями вроде бы перезаказывать не надо.

Проверьте в разделе Администрирования, во вкладке Конкурентные лицензии, Разрешения на продукты лицензирования, разрешено ли данному пользователям или группам, куда они входит, использовать конкурентные лицензии.

Показать все комментарии
Скрипты
Разработка

Есть функция проверки валидности email:

function CheckCommunications(Dataset) {
   var Result = false;
   var emailRegEx = new RegExp("^[_\.0-9a-zA-Z-]+@([0-9a-zA-Z][0-9a-zA-Z-]+\.)+[a-zA-Z]{2,6}$");
       if ((Dataset('Communication1TypeID') == '{7A628D16-D7D0-4979-B8BA-B64EF54A0366}') && !IsEmptyValue(Dataset('Communication1'))) {
           var emailStr=Dataset.Values('Communication1');
           Result = emailRegEx.test(emailStr);
        }
      if (!Result) {
      ShowErrorDialog('Проверьте правильность заполнения поля email!');
      return;
      }
     
}

Подскажите на каком событии её корректно вызывать перед записью в базу?
Пробовал на btnOKOnClick
function btnOKOnClick(Control) {
        if (!CheckAccountData()) {
            return;
        }
        scr_BaseDBEdit.btnOKOnClick(Control);

    var Dataset = dlData.Dataset;               // Validation email
    Dataset.Close();
    Dataset.Open();
        CheckCommunications(Dataset);  
        //Dataset.Close();                            //&

}
, но отрабатывает некорректно - проверять проверяет, но пишет в базу не валидный email.

Нравится

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

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

Данные то сохраняются раньше на строке

scr_BaseDBEdit.btnOKOnClick(Control);

Поэтому просто переделайте обе функции:

function btnOKOnClick(Control) { 
        if (!CheckAccountData()) {
            return;
        }
        if(!CheckCommunications(dlData.Dataset)) {
            return;
        }
        scr_BaseDBEdit.btnOKOnClick(Control);
}
 
function CheckCommunications(Dataset) {
   var Result = false;
   var emailRegEx = new RegExp("^[_\.0-9a-zA-Z-]+@([0-9a-zA-Z][0-9a-zA-Z-]+\.)+[a-zA-Z]{2,6}$"); 
       if ((Dataset('Communication1TypeID') == '{7A628D16-D7D0-4979-B8BA-B64EF54A0366}') && !IsEmptyValue(Dataset('Communication1'))) {
           var emailStr=Dataset.Values('Communication1');
           Result = emailRegEx.test(emailStr);
        } 
      if (!Result) {
      ShowErrorDialog('Проверьте правильность заполнения поля email!');      
      }
      return Result;      
}
Показать все комментарии
Скрипты
Разработка

Подскажите пожалуйста, как можно обнулить датасет в следующем случае:

function функция(StDataset, ParentWindow)
var Dataset             = GetOpenedDatasetByUSIWithFilter(DatasetUSI, FilterName, ParamValue, UniqueCode, DisableFieldsArray, DoDisableEvents);

        var Stop        = Dataset('Stop');                                     
       
    if (!IsZeroValue(Stop))  {
               
                        MessageBox(Стоит галка Стоп. Запись создана не будет!');
//Здесь перед выходом пробую очистить датасет, но не получается
                        Dataset.DisableEvents();
                        Dataset.Close();
                        return;
                       
                }

        for(Dataset.GotoFirst(), Counter = 0; ( !Dataset.IsEOF ); Counter++, Dataset.GotoNext()) {
.....
Dataset.Edit();
.....


 }
Dataset.Close();
}

Если Stop > 1, то вычисляем какие-то данные и заносим в БД.
Если Stop ==1, то выходим из функции, при этом очищаем датасет.

В случае Stop > 1, все нормально, данные пишутся в БД и при повторном вызове функции дата сет отрабатывает выделенную запись.
Но, если Stop ==1, т.е. мы ничего не хотим писать в БД и просто выйти с очисткой датасета.

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

Нравится

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

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

Спасибо за Ваше обращение. Мы зарегистрировали его в Службе технической поддержки и назначили специалиста, который сможет Вас компетентно проконсультировать по данному вопросу.

Алекс, а при отладке перед return какой Dataset,RecordsCount? Не очищается?

"Maxim Gritsenko" написал:

Алекс, а при отладке перед return какой Dataset,RecordsCount? Не очищается?


Не очищается. В датасете те строки, в которых при предыдущих вызовах был Stop ==1 и наша текущая строка. Если мы насильно удалим из базы эти строки (где был Stop ==1) или в этих строках сделаем Stop = 0, то из датасета они пропадают.

Что значит очистить датасет? Заполнить все колонки, кроме ID значением null? Удалить запись? Не совсем понятно... Опишите, пожалуйста, Вашу бизнес задачу.

Если у вас точно известно, что

var Dataset             = GetOpenedDatasetByUSIWithFilter(DatasetUSI, FilterName, ParamValue, UniqueCode, DisableFieldsArray, DoDisableEvents);

вернет одну строку (к примеру вы фильтруете по ID), то пишем просто:

if(!Stop) {
  //пишем данные
}

если это точно не известно то в цикле:

while(!Dataset.IsEOF) {
          var Stop = Dataset('Stop');
          if(!Stop) {
          Dataset.Edit();
          ...
          Dataset.Post();
          }
          Dataset.GotoNext();
}

пс: мне кажется, что функция GetOpenedDatasetByUSIWithFilter возвращает старый экземпляр датасета. Может поможет если напишите явно?

var Dataset = Services.GetNewItemByUSI('ds_Stop');
EnableDatasetFilters(Dataset, false);
ApplyDatasetFilter(Dataset, 'FilterName', FilterValue, true);
Dataset.Open();
....

"Олейник Дмитрий" написал:

пс: мне кажется, что функция GetOpenedDatasetByUSIWithFilter возвращает старый экземпляр датасета. Может поможет если напишите явно?

var Dataset = Services.GetNewItemByUSI('ds_Stop');

EnableDatasetFilters(Dataset, false);

ApplyDatasetFilter(Dataset, 'FilterName', FilterValue, true);

Dataset.Open();

....

С уважением,

Олейник Дмитрий

На GetOpenedDatasetByUSIWithFilter очень много завязано, поэтому поменять на GetNewItemByUSI просто не получится.
Вот последовательность действий:
Если на выделенной строке (ID=A1) в мастере Stop <> 1, то пишутся в базу некие данные в деталь. Датасет А1.
Если на выделенной строке (ID=A2) в мастере Stop <> 1, то пишутся в базу некие данные в деталь. Датасет А2.
Если на выделенной строке (ID=A3) в мастере Stop == 1, то НЕ пишем в базу данные в деталь и показываем окно-предупреждение, что Stop == 1 и ничего нельзя писать в БД. Датасет А3.
Если на выделенной строке (ID=A4) в мастере Stop <> 1, то пишутся в базу некие данные в деталь. При этом dataset обращается к ID = A3, обрабатывает, затем к A4. Т.е. A3 сохраняется в датасете. Датасет А3, А4.
Если же теперь мы в A3 сделаем Stop <> 1 и отработаем эту строку. То она исчезает из дата сета. Датасет А3.
Если на выделенной строке (ID=A5) в мастере Stop <> 1, то пишутся в базу некие данные в деталь. Датасет А5.
Есть ли какой-нибудь способ принудительной очистки данного датасета в этом случае?
Пробовал вариант:

if(!Stop) {
  //пишем данные
}

Но то же самое.

Правильно ли я понял, что выделенная строка с разными ID - это строки, которые попали в датасет после его открытия через GetOpenedDatasetByUSIWithFilter ?
Если так, то по этому датасету вы ходите в цикле и при определенных условиях что-то пишете в детали? Каким образом с 4-ой строки вы перемещаетесь на 3-ую, и снова на 4-ую?

Если же теперь мы в A3 сделаем Stop <> 1

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

В общем, все-ровно не понял как это все у вас устроено. Можете прикрепить весь свой код сюда полностью, а также объясните, пожалуйста, все таки: все эти строки обрабатываются в одном цикле, или эта функция вызывается несколько раз? Если несколько - то с какими параметрами, и меняете ли Вы uniqueCode для датасета? Сбрасываются ли фильтра?

Более подробно:
Выбираю строку в гриде. В контекстном меню - Действия - ВыполнитьДействие. Попадаем сюда:

function amiOnExecute(ActionMenuItem, Sender) {
	var OpDataset  = dlOp.Dataset;
//Уже сюда вынес проверку на Stop
	var Stop = OpDataset('Stop'); 
	    if (!IsZeroValue(Stop)) {
	    MessageBox('Стоит галка Stop ! Ничего в базу не пишем!');
//Здесь пытаюсь очистить датасет, как-будто я не выбирал строку в гриде (но не чистит)
	    OpDataset.Close();
	    OpDataset.Open();
	    return false;
	    }
 
	var Result = hConfirmation(OpDataset, OpWorkspace.COpWindow);
}

Далее следующая функция для проверки:

function hConfirmation(OpDataset, ParentWindow) 
 
{
	var Message = FormatStr('Вы действительно хотите ...' , 
					GetSystemParameterValueEx('ToPay', true));
	if (ShowConfirmationDialog(Message) != wmrYes) {
		return;
	}
 
 
	finalEv(OpDataset, ParentWindow);	
}

И наша финальная функция, которая отрабатывает и пишет в базу:

function finalEv(OpDataset, ParentWindow) {
var DatasetUSI	= 'ds_COp';
var Dataset		= GetOpenedDatasetByUSIWithFilter(DatasetUSI,	'CanEv', true, 'finalEv', null, true);
....
//Вот в этом цикле пишутся данные в БД. 
for(Dataset.GotoFirst(), Counter = 0; ( !Dataset.IsEOF ); Counter++, Dataset.GotoNext()) {
.....
Dataset.Edit();
.....
 
 }
Dataset.Close();
 
}

Хотелось бы, если Stop ==1, то выходим из функции, при этом очищаем датасет.
Судя по всему GetOpenedDatasetByUSIWithFilter запоминает строку (OLD), когда мы отрабатывали:

function amiOnExecute(ActionMenuItem, Sender) {
        var OpDataset  = dlOp.Dataset;
//Уже сюда вынес проверку на Stop
        var Stop = OpDataset('Stop'); 
            if (!IsZeroValue(Stop)) {
            MessageBox('Стоит галка Stop ! Ничего в базу не пишем!');
//Здесь пытаюсь очистить датасет, как-будто я не выбирал строку в гриде (но не чистит)
            OpDataset.Close();
            OpDataset.Open();
            return false;
            }
 
        var Result = hConfirmation(OpDataset, OpWorkspace.COpWindow);
}

и при выполнения Действия над другой новой (new) строкой (где Stop <>1) сначала выполняется обработка этой new строки (мы её просто выбираем в гриде), а затем тут же отрабатывается наша OLD строка.
Как очистить датасет от этой (этих) OLD строк, как будто их вообще небыло?
Это
OpDataset.Close();
OpDataset.Open();
не помогает.
Что-то такое
OpDataset.Clear();
не поддерживается?

function amiOnExecute(ActionMenuItem, Sender) {
        var OpDataset  = dlOp.Dataset;
        var Stop = OpDataset('Stop'); 
        if (!IsZeroValue(Stop)) {
            MessageBox('Стоит галка Stop ! Ничего в базу не пишем!');            
            return false;
        }
        var Result = hConfirmation(OpDataset, OpWorkspace.COpWindow);
}

Переоткрывать датасет

OpDataset.Close();
OpDataset.Open();

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

function Main() {	
	var Dataset = Services.GetNewItemByUSI('ds_CommunicationType');
	Dataset.Open();
        //Dataset.RecordNumber == 1;
	Dataset.GotoNext();
        //Dataset.RecordNumber == 2;
	Dataset.Close();
	Dataset.Open();
        //Dataset.RecordNumber == 1; 
}

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

Таким образом, что мы имеем:

первую функцию-действие лучше переписать так:

function amiOnExecute(ActionMenuItem, Sender) {
        var OpDataset  = dlOp.Dataset;
        var Stop = OpDataset('Stop'); 
        if (!IsZeroValue(Stop)) {
            MessageBox('Стоит галка Stop ! Ничего в базу не пишем!');            
            return false;
        }
        var Result = hConfirmation(OpDataset, OpWorkspace.COpWindow);
}

функция hConfirmation будет выполнена только в том случае, если в текущей выделенной строке, для которой было запущено действие, поле Stop не заполнено.

Вторая функция остается без изменений:

function hConfirmation(OpDataset, ParentWindow) 
 
{
        var Message = FormatStr('Вы действительно хотите ...' , 
                                        GetSystemParameterValueEx('ToPay', true));
        if (ShowConfirmationDialog(Message) != wmrYes) {
                return;
        }
 
 
        finalEv(OpDataset, ParentWindow);       
}

а вот с третьей непонятно. Самое интересное то, что вы ей передаете датасет реестра (OpDataset), который позиционирован на нужной строке (т.е. та в которой стоп = 0), а также ParentWidnow, но при этом нигде их не используете. Покажите как Вы его используете, потому что в текущем примере OLD строка никак не может быть обработана, если вы не выполняете никаких манипуляций , которые приводят к смене текущей активной строки, что-то вроде этого:

OpDataset.GotoNext();
OppDataset.Close();
OppDataset.Open();

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

function amiOnExecute(ActionMenuItem, Sender) {
        var OpDataset  = dlOp.Dataset;
        var Stop = OpDataset('Stop'); 
        if (!IsZeroValue(Stop)) {
            MessageBox('Стоит галка Stop ! Ничего в базу не пишем!');            
            return false;
        }
        var myValue1 = OppDataset('myVaule1');
        var myValue2 = OppDataset('myVaule2');
        var myValue3 = OppDataset('myVaule3');
        var Result = hConfirmation(myValue1,myValue2, myValue3,  OpWorkspace.COpWindow);
}

"Олейник Дмитрий" написал:

а вот с третьей непонятно. Самое интересное то, что вы ей передаете датасет реестра (OpDataset), который позиционирован на нужной строке (т.е. та в которой стоп = 0), а также ParentWidnow, но при этом нигде их не используете. Покажите как Вы его используете, потому что в текущем примере OLD строка никак не может быть обработана, если вы не выполняете никаких манипуляций , которые приводят к смене текущей активной строки, что-то вроде этого:

OpDataset.GotoNext();

OppDataset.Close();

OppDataset.Open();

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

function amiOnExecute(ActionMenuItem, Sender) {

        var OpDataset  = dlOp.Dataset;

        var Stop = OpDataset('Stop');

        if (!IsZeroValue(Stop)) {

            MessageBox('Стоит галка Stop ! Ничего в базу не пишем!');            

            return false;

        }

        var myValue1 = OppDataset('myVaule1');

        var myValue2 = OppDataset('myVaule2');

        var myValue3 = OppDataset('myVaule3');

        var Result = hConfirmation(myValue1,myValue2, myValue3,  OpWorkspace.COpWindow);

}

С уважением,

Олейник Дмитрий


Манипуляции выполняются в этом цикле:

//Вот в этом цикле пишутся данные в БД. 
for(Dataset.GotoFirst(), Counter = 0; ( !Dataset.IsEOF ); Counter++, Dataset.GotoNext()) {
.....
Dataset.Edit();
.....
 
 }
Dataset.Close();
 
}

Сначала выполняется текущая активная строка грида с Stop=0(null), а затем в этом цикле выполняется OLD строка (с Stop=1), которую вроде бы как мы покинули здесь:

if (!IsZeroValue(Stop)) {
            MessageBox('Стоит галка Stop ! Ничего в базу не пишем!');
            return false;
            }

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

Можно ли очистить наш OpDataset вообще как-нибудь, что-бы там не было никаких строк old?
И если можно, то в этом месте

if (!IsZeroValue(Stop)) {
            MessageBox('Стоит галка Stop ! Ничего в базу не пишем!');
// Здесь очищаем наш дата сет от нашей строки, которая попала сюда.
            return false;
            }

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

Разобрался с вопросом. Спасибо!

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