отчет
фильтр
Отчёты
Разработка

Есть запрос в котором нужно фильтровать данные по незаполненным полям в БД.
На форме фильтрации есть чекбоксы, при выбранном чексе будет включаться фильтн на is null.

var DatasetUSIList = ReportPreviewer.Report.Attributes('DatasetUSIList');
       
        for (var i = 0; i DatasetUSIList.length; i++) {
            var ReportDatasetUSI = DatasetUSIList[i];
            var ReportDataset = ReportPreviewer.DatasetByUSI(ReportDatasetUSI);
            ReportDataset.Close();
               
                ApplyDatasetFilter(ReportDataset, 'FromDate', FromDate, FromDateFilterEnabled);
                ApplyDatasetFilter(ReportDataset, 'ToDate', ToDate, ToDateFilterEnabled);
                                                                               
        var BranchIDs = edtBranchIDs.Tag.split(',');
                ApplyDatasetIncludeFilter(ReportDataset, 'BranchIDs', BranchIDs, BranchFilterEnabled);         
               
                var OwnerIDs = edtOwnerIDs.Tag.split(',');
                ApplyDatasetIncludeFilter(ReportDataset, 'OwnerIDs', OwnerIDs, OwnerFilterEnabled);              
               
                //Включение доп параметров
                if(Fields.IsChecked != false){
                        EnableDatasetFilters(ReportDataset, true, 'FieldsIDin');
        }
                //             
        }

Но в скрипте я его немогу включить. Подскажите что я делаю не так?

Нравится

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

Не понятно, т.е. код в скрипте отрабатывает, но фильтры в запрос не добавляются?

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

Не понятно, т.е. код в скрипте отрабатывает, но фильтры в запрос не добавляются?

С уважением,

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


Совершенно верно, так как параметры находятся в подзапросе, и как к ним добраться я не знаю!

Ну, значение параметра можно установить так:

SetParameterValue(myDataset.SelectQuery.Parameters, 'myParamName', 'myParamValue');

А включить фильтр в подзапросе можно либо сразу же в сервисе, либо вручную:

myDataset.SelectQuery.Items(0).Filters.ItemsByName('myFilter').IsEnabled = true;
Показать все комментарии
3.x
Технические вопросы
Разработка

Здравствуйте! Мы планируем перейти от версии 3.2 к 3.4. Во что это выльется?

Нравится

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

"Тюльпа Владимир" написал:Мы планируем перейти от версии 3.2 к 3.4. Во что это выльется

1. Купить лицензии.
2. Доработки я так понимаю есть :smile: Поэтому мое скромное мнение переносить в два этапа: делаем все доработки заново на "коробочной" 3.4.1 и затем когда структура баз одинакова и все доработки логики и интерфейса сделаны "переливаем" данные в новую базу с помощью RedGate (у вас же MS SQL? С Firebird будет веселее)

Оффтопик - смысл перехода?

Есть специальные пакеты перехода, которые может подготовить поддержка. Если доработок много - это выльется в неделю-две отладки обновленной системы. Если доработок нет, или их минимальное количество - все будет хорошо. :)

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

Добрый день
Почему не работает условие описанное в коде

var Dataset = DataGrid.DatasetLink.Dataset;
var data= '30.09.2014'

if (Dataset ('CreatedOn') > StrToDate(data))
{
Color.Value= clPink; }

правильно ли пытаюсь сравнить даты?

Нравится

2 комментария
var Dataset = DataGrid.DatasetLink.Dataset;
var data= '30.09.2014'
 
if (new Date(Dataset('CreatedOn')) > StrToDateEx(data))
{
Color.Value= clPink; }
function StrToDateEx(stringDate) {
	stringDate = stringDate.split('.');
        if(stringDate.length != 3) {
              return null;
        }	
	return new Date(stringDate[2], stringDate[1]-1, stringDate[0]);
}

спасибо!

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

Добрый день!
При авторизации Terrasoft XRM 3.x по TCP/IP (СУБД Firebird) возникает ошибка "Ошибка конфигурации. Лицензия для модуля не найдена". Пользователь sysdba. С локального ПК авторизация проходит. На удалённом проходит тестовое подключение. Лицензии конкурентные.
Заранее спасибо за помощь!

Нравится

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

Здравствуйте.
При авторизации с использованием конкурентных лицензий строка подключения должна визуально выглядеть точно так же, как и на той машине, с которой формировался запрос на лицензии. Допускаю, что у Вас база расположена на локальном компьютере и указан тип подключения "local". С такими настройками, соответственно, по сети подключиться не получится. Рекомендую указать на локальной машине подключение как по сети к самому себе (указать TCP/IP и свой IP). После чего перезаказать лицензии.

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

Задача - запретить удаление выполненных операций всем пользователям, кроме нескольких определенных.
Что делаю - на событие OnDatasetBeforeDelete для ds_Cashflow в скрипте ds_CashflowScript пишу функцию

function SelfOnDatasetBeforeDelete(Dataset) {
        ContactID = Connector.CurrentUser.ContactID ;
        CashflowScript.StatusID = GetFieldValueFromDisabledField(Dataset, 'StatusID');
        if (CashflowScript.StatusID=='{FDEA47BE-53FE-4730-BF4F-4F44C3B5D61A}'){
           if (ContactID != '{32E85247-DE68-4C6A-B032-06F5CDFB2B3A}'  &&
                 ContactID != '{E2093D56-49ED-4D4D-B69E-C9FF0623DE95}'  &&
                 ContactID != '{ED75744C-BC2C-469C-8993-8473E23E7F06}'  &&
                 ContactID != '{14925854-AAFD-4516-8A23-F2B5312F4C63}'){
                 ShowInformationDialog('У Вас нет прав удалять выполненную операцию');
                 return;
                  }
            }
        }

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

Нравится

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

Мне кажется, такую логику лучше сделать путём раздачи прав на группу таблиц этого раздела.

Это не то, что мне необходимо. Потому что удаление операций других состояний, кроме " выполненные" , допускается. Мне надо сделать именно так, как я описала.

По идее полный обработчик выглядит так (3.4.1)

ds_CashflowOnDatasetBeforeDelete(Dataset, DoDelete)

если внутри по условию присвоить

DoDelete.Value = true;

то удаление должно отмениться

У меня в 3.3.2 функция выглядит без DoDelete. Если его туда дописать, то ничего не изменится

Виктория, странно, у меня в 3.3.2 есть параметр DoDelete. Конструкция ниже работает:

function ds_CashflowOnDatasetBeforeDelete(Dataset, DoDelete) {
 
	CashflowScript.StatusID = GetFieldValueFromDisabledField(Dataset, 'StatusID');
 
	if (CashflowScript.StatusID =='{FDEA47BE-53FE-4730-BF4F-4F44C3B5D61A}')  { 	
		ShowInformationDialog('У Вас нет прав удалять выполненную операцию');
	    DoDelete.Value = false;
	}   

}

Но можно также создать обработчик события кнопки "Удалить" грида Операций, в которой реализовать аналогичное условие:

function btnDeleteOnClick(Control) {
 
	 if (grdData.DatasetLink.Dataset.ValAsGUID('StatusID')  == '{FDEA47BE-53FE-4730-BF4F-4F44C3B5D61A}')  {
	  	ShowInformationDialog('У Вас нет прав удалять выполненную операцию');
	 }
	 else
	 	scr_BaseGridArea.btnDeleteOnClick(Control);
}

"Безродный Андрей" написал:Но можно также создать обработчик события кнопки "Удалить" грида Операций, в которой реализовать аналогичное условие:

Кнопочка delete все равно будет работать по выделенной записи :)

"Александр Кудряшов" написал:
Безродный Андрей пишет:

Но можно также создать обработчик события кнопки "Удалить" грида Операций, в которой реализовать аналогичное условие:

Кнопочка delete все равно будет работать по выделенной записи :)


Александр,

проверил:

по кнопке Delete на клавиатуре аналогично появляется окно с предупреждением (бинарные файлы 3.3.2.311):

http://i68.fastpic.ru/big/2014/0930/1d/cf02d7f1e5909e18df53bdfa5f1de61d.png

У меня только в скрипте wnd_CashflowGridAreaScript есть функция с DoDelete, называется function dlDataOnDatasetBeforeDelete(Dataset, DoDelete).

Сейчас попробую привязаться к кнопке "Удалить"

"Безродный Андрей" написал:по кнопке Delete на клавиатуре аналогично появляется окно с предупреждением (бинарные файлы 3.3.2.311)

Спасибо, вот этого я не знал... или хорошо забыл :smile:

по кнопке Удалить у меня работает только так (без открытия и закрытия Датасета ругается).
Но самое противное, что при такой работе очень заметно тормозит, зависает на минуту-другую. Работать так не возможно. Увы.

function btnDeleteOnClick(Control) {
 
	var CashflowDataset = CashflowGridArea.CashflowDataset;
	 ContactID = Connector.CurrentUser.ContactID ;
	 	 CashflowDataset.Open();
	   StatusID = CashflowDataset.ValAsGUID('StatusID');
	  CashflowDataset.Close();
 
	 //если статус операции = выполнена, а изменяющий не из группы упр.фин, то не удалять
     	if (StatusID=='{FDEA47BE-53FE-4730-BF4F-4F44C3B5D61A}'){
     	if (ContactID != '{32E85247-DE68-4C6A-B032-06F5CDFB2B3A}'  &&
		 ContactID != '{E2093D56-49ED-4D4D-B69E-C9FF0623DE95}'  &&
		 ContactID != '{ED75744C-BC2C-469C-8993-8473E23E7F06}'  &&
		 ContactID != '{14925854-AAFD-4516-8A23-F2B5312F4C63}'){
     	ShowInformationDialog('У Вас нет прав удалять выполненную операцию НОВОЕ');
     	return;
     				  }   else  scr_BaseGridArea.btnDeleteOnClick(Control);
 
	} else 	scr_BaseGridArea.btnDeleteOnClick(Control);
 
} 

Поэтому возвращаюсь к первоначальному вопросу - нельзя ли все-таки как-то правильно использовать событие OnDatasetBeforeDelete для ds_Cashflow в скрипте ds_CashflowScript?

Т.к. везде по системе для отображения операций используется грид wnd_CashflowGridArea (за возможно единственным исключением - окном выбора wnd_SelectData), то используйте свой код с первого же вашего поста, только на событии

У меня только в скрипте wnd_CashflowGridAreaScript есть функция с DoDelete, называется function dlDataOnDatasetBeforeDelete(Dataset, DoDelete).

и не забудьте дописать

DoDelete.Value = false; 

Если это критично, и хочется точно знать что лазеек в безопасности нет, ни от куда нельзя будет удалить операцию - пишите триггер на таблицу.

Дмитрий, не поверите, подправила функцию

function dlDataOnDatasetBeforeDelete(Dataset, DoDelete) {
	 ContactID = Connector.CurrentUser.ContactID ;
      StatusID = Dataset.ValAsGUID('StatusID');
        if (StatusID=='{FDEA47BE-53FE-4730-BF4F-4F44C3B5D61A}'){
           if (ContactID != '{32E85247-DE68-4C6A-B032-06F5CDFB2B3A}'  &&
                 ContactID != '{E2093D56-49ED-4D4D-B69E-C9FF0623DE95}'  &&
                 ContactID != '{ED75744C-BC2C-469C-8993-8473E23E7F06}'  &&
                 ContactID != '{14925854-AAFD-4516-8A23-F2B5312F4C63}'){
                 ShowInformationDialog('У Вас нет прав удалять выполненную операцию');
                  DoDelete.Value=false;
 
 
                  }
            }
}

Сообщение появляется, когда положено, но операция все равно УДАЛЯЕТСЯ.
Все так же как и было изначально. :(
Зато работает быстро.

Виктория, это какая-то фантастика - никогда подобного не встречал. Вы обновлялись до последней версии бинарников? Попробуйте, как минимум на 3.3.2.311.

Виктория,

действительно, проверьте на последней версии бинарных файлов (3.3.2.311).

Как я писал ранее, оба варианта на версии бинарных файлов 3.3.2.311 и конфигурации версии 3.3.2.130 работают корректно.

Если обновление не сработает, пришлите на support@terrasoft.ru копию базы, - посмотрим.

Обновление на новые бинарные файлы помогло!

Показать все комментарии
Отчёты
Разработка

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

DROP TABLE ##t
select ROW_NUMBER() over (order by [CreatedOn] DESC) as rn, [ID], [CreatedOn], [BasicPrice],OfferingID,RecordID,OfferingName INTO ##t
        from [tbl_OfferingPriceLog]
         WHERE PriceCategoryID = 'B46B83EF-39AD-4687-B375-AB60EF931309'
------------------------------------------------------
DROP TABLE ##m
SELECT A.[ID] ,A.[CreatedOn] ,A.[BasicPrice],A.OfferingID
      ,ISNULL(A.[BasicPrice] - (select top 1 b.[BasicPrice] from ##t B,0) AS DELTAPRICE,
      CASE WHEN ISNULL(A.[BasicPrice] - (select top 1 b.[BasicPrice] from ##t B,0) = 0 THEN 0 ELSE
       1 END AS COUNTDELTA INTO ##m
  FROM ##t A
-------------------------------------------------------
  SELECT o.Name AS Name, SUM(a.COUNTDELTA)AS Count
  FROM ##m A
  LEFT OUTER JOIN tbl_Offering o ON o.ID = a.OfferingID
  GROUP BY OfferingID,o.Name
  ORDER BY Count DESC
 -------------------------------------------------------

Нравится

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

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

Показать все комментарии
Job Manager
рассылка
Технические вопросы
Разработка

Есть потребность на ТС340 авотматические высылать рассылку. Создал скирпт которыи вызывает стандартный скрипт автоматическои рассыльки. Протестировал работает - письмо формирует и отдает на Оутлук. Тот самы скрипт поставил на Job Manager. Вижу что в Job Manager истории запиcь что скрипт стартовал и все - висит, письма не высылает.
В чем тут порблема?

function SendAccountMassMailForGenerated(){

        var MassMailDataset = Services.GetNewItemByUSI('ds_MassMail');
        EnableDatasetFilters(MassMailDataset, true, 'IsReadySendGenerated');
        MassMailDataset.Open();
        while (!MassMailDataset.IsEOF) {
                try {
                        SendAccountMassMail(MassMailDataset('ID'));
                        MassMailDataset.GotoNext();
                } catch(e) {
                }
        }      
        MassMailDataset.Close();
}

Нравится

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

Здравствуйте, Альбертас.

А если поставить дебаггер в скрипте, а затем дождаться его запуска, на какой строчке будет остановка?

Поставил дебаггер. Но он не выскакивает. Невернека от того что он запускается от SYSTEM.

Если из планировщика Terrasoft логика не срабатывает, можно использовать планировщик Windows.

Спасибо. Применил этот.

Показать все комментарии
SQL
запросы
продажи в работе
Фильтры
Разработка

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

SELECT count (ID) FROM tbl_Opportunity
WHERE EXISTS
(SELECT ID FROM
(SELECT top (1) CreatedOn,StatusName, StageStage, Title, ID, RecordID, Cash, Revenue  FROM tbl_OpportunityLog WHERE
[tbl_OpportunityLog].[RecordID] = [tbl_Opportunity].[ID]AND
[tbl_OpportunityLog].[CreatedOn] = :CreatedOn
ORDER BY [tbl_OpportunityLog].[CreatedOn] DESC) AS OpportunityTable
WHERE [OpportunityTable].[StatusName] = :STATUS AND
 ([OpportunityTable].[StageStage] =:Stage1 OR
 [OpportunityTable].[StageStage] = :Stage2 OR
 [OpportunityTable].[StageStage] = :Stage3))
GROUP BY
        [tbl_Opportunity].[Title]

Остался открытым вопрос , как изменить этот запрос, чтобы получить ответ на вопрос "какой был потенциал этих продаж на требуемую дату".
У меня получается вытянуть только сегодняшний потенциал - sum ([tbl_Opportunity].[Cash]) , на все другие изменения запроса sql ругается - sum ([tbl_OpportunityLog].[Cash]), sum([OpportunityTable].[Cash]....
А варианты запросов сразу к журналу изменений приводят к дублированию продаж.

Нравится

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

Вот навернула тут inner join, чтобы было можно выбирать данные из журнала изменений.
Остался вопрос (написала его в тексте запроса, чтобы было понятнее)

SELECT [tbl_Opportunity].[Title], 
CONVERT(DATE, [tbl_Opportunity].[CreatedOn], 102) As CreatedOn, 
sum([tbl_Opportunity].[Cash])/count([tbl_OpportunityLog].[id]) as CashToday,
sum([tbl_OpportunityLog].[Cash])/count([tbl_OpportunityLog].[id]) AS [AvgCashLog]
 
FROM tbl_Opportunity inner join [tbl_OpportunityLog] on 
 [tbl_OpportunityLog].[RecordID] = [tbl_Opportunity].[ID] and
[tbl_OpportunityLog].[CreatedOn] <= CONVERT(DATETIME, '2014-03-31 00:00:00', 102) and
[tbl_OpportunityLog].[StatusName] = :STATUS AND
 ([tbl_OpportunityLog].[StageStage] =:Stage1 OR
 [tbl_OpportunityLog].[StageStage] = :Stage2 OR
 [tbl_OpportunityLog].[StageStage] = :Stage3) 
 
// в ЭТОМ МЕСТЕ НАДО еще добавить условие на выбор записи журнала изменений с МАКСИМАЛЬНОЙ датой CreatedOn. КАК?
 
 
 WHERE exists
(SELECT ID,StatusName, StageStage, Title, RecordID, Cash, Revenue from 
(Select top (1) CreatedOn,StatusName, StageStage, Title, ID, RecordID, Cash, Revenue  from tbl_OpportunityLog WHERE 
[tbl_OpportunityLog].[RecordID] = [tbl_Opportunity].[ID]and
[tbl_OpportunityLog].[CreatedOn] <= CONVERT(DATETIME, '2014-03-31 00:00:00', 102)
ORDER BY [tbl_OpportunityLog].[CreatedOn] Desc) As OpportunityTable
Where [OpportunityTable].[StatusName] = :STATUS AND
 ([OpportunityTable].[StageStage] =:Stage1 OR
 [OpportunityTable].[StageStage] = :Stage2 OR
 [OpportunityTable].[StageStage] = :Stage3)) 
GROUP BY
	[tbl_Opportunity].[Title], [tbl_Opportunity].[CreatedOn]

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

where [tbl_OpportunityLog].[CreatedOn] = (select max([CreatedOn]) from [tbl_OpportunityLog])

Два раза подряд WHERE такого sql не понимает.
Скобки тоже не помогли.

Если вообще убрать WHERE и продолжить писать условия через and для выборки INNER JOIN, то получится пустое множество.

Виктория, я демонстрировал конструкцию.
В вашем запросе она должна располагаться так:

SELECT [tbl_Opportunity].[Title], 
CONVERT(DATE, [tbl_Opportunity].[CreatedOn], 102) AS CreatedOn, 
sum([tbl_Opportunity].[Cash])/count([tbl_OpportunityLog].[id]) AS CashToday,
sum([tbl_OpportunityLog].[Cash])/count([tbl_OpportunityLog].[id]) AS [AvgCashLog]
 
FROM tbl_Opportunity INNER JOIN [tbl_OpportunityLog] ON 
 [tbl_OpportunityLog].[RecordID] = [tbl_Opportunity].[ID] AND
[tbl_OpportunityLog].[CreatedOn] <= CONVERT(DATETIME, '2014-03-31 00:00:00', 102) AND
[tbl_OpportunityLog].[StatusName] = :STATUS AND
 ([tbl_OpportunityLog].[StageStage] =:Stage1 OR
 [tbl_OpportunityLog].[StageStage] = :Stage2 OR
 [tbl_OpportunityLog].[StageStage] = :Stage3) 
 
 WHERE EXISTS
(SELECT ID,StatusName, StageStage, Title, RecordID, Cash, Revenue FROM 
(SELECT top (1) CreatedOn,StatusName, StageStage, Title, ID, RecordID, Cash, Revenue  FROM tbl_OpportunityLog WHERE 
[tbl_OpportunityLog].[RecordID] = [tbl_Opportunity].[ID]AND
[tbl_OpportunityLog].[CreatedOn] <= CONVERT(DATETIME, '2014-03-31 00:00:00', 102)
ORDER BY [tbl_OpportunityLog].[CreatedOn] DESC) AS OpportunityTable
WHERE [OpportunityTable].[StatusName] = :STATUS AND
 ([OpportunityTable].[StageStage] =:Stage1 OR
 [OpportunityTable].[StageStage] = :Stage2 OR
 [OpportunityTable].[StageStage] = :Stage3)) AND
 [tbl_OpportunityLog].[CreatedOn] = (SELECT max([CreatedOn]) FROM [tbl_OpportunityLog])
GROUP BY
        [tbl_Opportunity].[Title], [tbl_Opportunity].[CreatedOn]

Так, как Вы написали , тоже же получается пустое множество.

Да и не нужна там эта строка.
После WHERE EXISTS очень правильный запрос уже написан. Он одновременно 1) проверяет существуют ли в журнале изменений записи, дата которых меньше, чем указанная, а состояния равны указанным. Таких записей может быть несколько 2) и выбирает с помощью top (1) CreatedOn и сортировки DESC максимальную из дат , которая удовлетворяет требованию.

Проблема в другом. Проблема в том, что никак не получается узнать какая же Сумма потенциала была на тот момент в этой продаже. Не получается обратиться к OpportunityTable, которая сформирована таким образом.
Чтобы это как-то исправить я добавила INNER JOIN. Те. тут я хочу повторить эту же самую выборку, но таким образом, чтобы я могла к ней обращаться. Поэтому 1) я повторила ограничение по дате, по статусу и по состоянию. 2) Но никак не могу выбрать именно максимальную по дате запись журнала изменений.

ПОЛУЧИЛОСЬ! надо было просто не бояться впихнуть еще один селект

SELECT [tbl_Opportunity].[Title], 
CONVERT(DATE, [tbl_Opportunity].[CreatedOn], 102) As CreatedOn, 
sum([tbl_Opportunity].[Cash])/count([tbl_OpportunityLog].[id]) as CashToday,
sum([tbl_OpportunityLog].[Cash])/count([tbl_OpportunityLog].[id]) AS [CashLogOnDate]
 
FROM tbl_Opportunity inner join [tbl_OpportunityLog] on 
 [tbl_OpportunityLog].[RecordID] = [tbl_Opportunity].[ID] and
[tbl_OpportunityLog].[CreatedOn] <= CONVERT(DATETIME, '2014-03-31 00:00:00', 102) and
[tbl_OpportunityLog].[StatusName] =:STATUS AND
 ([tbl_OpportunityLog].[StageStage] =:Stage1 OR
 [tbl_OpportunityLog].[StageStage] = :Stage2 OR
 [tbl_OpportunityLog].[StageStage] = :Stage3)and
 [tbl_OpportunityLog].[CreatedOn] = (SELECT max([tbl_OpportunityLog1].[CreatedOn]) from  [tbl_OpportunityLog] as   [tbl_OpportunityLog1] 
 where  
 [tbl_OpportunityLog1].[RecordID] = [tbl_Opportunity].[ID] and
[tbl_OpportunityLog1].[CreatedOn] <= CONVERT(DATETIME, '2014-03-31 00:00:00', 102) and
[tbl_OpportunityLog1].[StatusName] = :STATUS AND
 ([tbl_OpportunityLog1].[StageStage] =:Stage1 OR
 [tbl_OpportunityLog1].[StageStage] = :Stage2 OR
 [tbl_OpportunityLog1].[StageStage] = :Stage3)
  )
 WHERE exists
(SELECT ID,StatusName, StageStage, Title, RecordID, Cash, Revenue from 
(Select top (1) CreatedOn,StatusName, StageStage, Title, ID, RecordID, Cash, Revenue  from tbl_OpportunityLog WHERE 
[tbl_OpportunityLog].[RecordID] = [tbl_Opportunity].[ID]and
[tbl_OpportunityLog].[CreatedOn] <= CONVERT(DATETIME, '2014-03-31 00:00:00', 102)
ORDER BY [tbl_OpportunityLog].[CreatedOn] Desc) As OpportunityTable
Where [OpportunityTable].[StatusName] = :STATUS AND
 ([OpportunityTable].[StageStage] =:Stage1 OR
 [OpportunityTable].[StageStage] = :Stage2 OR
 [OpportunityTable].[StageStage] =:Stage3))
GROUP BY
	[tbl_Opportunity].[Title], [tbl_Opportunity].[CreatedOn]
Показать все комментарии
Fast Report
отчеты
платежные реквизиты
счет
Отчёты
Разработка

Добрый день, коллеги.

Не нашел явного решения поэтому прошу помощи в решение задачи.

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

В идеале хотелось бы реализации такого типа, что при создании отчета появлялось окно фильтра и там можно было бы выбрать основные платежные реквизиты, которое заполнили бы бланк. Такое вообще возможно, а то у меня сомнения, что так можно? И что проще будет?

Нравится

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

Забыл уточнить. софт Terrasoft CRM 3.3.2.127

Павел, самым простым вариантом, как по мне, будет следующее:

1. Добавить в карточку платежного реквизита поле "По умолчанию для печати счета" с типом булево.
2. В сервисе sq, который используется для построения отчета, добавить параметр с типом целое число и значением 1, и в блок WHERE добавить уловие:

tbl_AccountBillingInfo.ПоУмолчаниюДляПечатиСчета = Parameter:.ПоУмолчаниюДляПечатиСчета

Тогда при печати счета, будет браться та строка, которая отмечена галочкой "По умолчанию для печати счета".
Но, если такой галочки ни у одной записи не будет - тогда в отчет не попадет ничего.

Если такой вариант не нравится, можно пункт 2 не делать, а просто в дизайнере отчета добавить фильтр по полю "По умолчанию для печати счета", которое если заполнить - в счет попадет строка с отмеченной галочкой, а если не заполнить - строка с не отмеченной галочкой.

Дмитрий,

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

Да, все верно.
Фильтры можно преднастроить в сервисе отчета через TS Administrator.

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

Добрый день!
Почему-то не не обновляется объект IDataGrid.
Смотрю ActiveView.Items(1).DataField.DisplayValue там одно значение, а реально на экране совсем другое. Особенность грида в том что в DatasetLink указан редактируемый MemoryDataset, в котором так же установлено нормальное значение.
Обновляться прекращает после того как в форме нажимаешь ОК (не важно редактировался ли MemoryDataset). После чего всегда визуально отображается содержимое формы по которой был клик ОК, не смотря на то что открывается совсем другое содержимое...

Нравится

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

Ммм, обращаться к активной (текущей выделенной) строке нужно так:

DataGrid.DatasetLink.Dataset.DataFields('ID').Value;

И заметьте, т.к. это редактируемый грид, значение в DataField'е обновится только при выходе из режима редактирования ячейки (либо после нажатия на Enter)

"Олейник Дмитрий" написал:Ммм, обращаться к активной (текущей выделенной) строке нужно так:

DataGrid.DatasetLink.Dataset.DataFields('ID').Value;

Дмитрий, добрый день! Возможно я "ммм" не очень понятно пишу, но еще раз подчеркну

"AlexLS" написал:в DatasetLink указан редактируемый MemoryDataset, в котором так же установлено нормальное значение

"Олейник Дмитрий" написал:при выходе из режима редактирования ячейки

никакого редактирования не происходило, только открытие формы в которой в датасете и в гриде дебаггер показывает правильные значения а "глаза" видят значения из той формы в которой последний раз был апдейт/инсерт!

Алекс, добрый день.

Все еще не понял про "нормальные значения".

Ни разу не сталкивался с таким поведением. Грид не кеширует значения датасета. Мне кажется чтото не так с датасетом, привязанным к гриду, вернее скорее всего датасет, в котором корректные значения не привязан к гриду. Можете написать кейс воспроизведения, при котором грид визуально отображает данные старой (насколько я понял) формы?
Я также, желательно, приведите код заполнения memoryDataset'a.

В GridAreaOnPrepare пишу:

if (Assigned(ParentDataset = GetAttribute(Window, 'ParentDataset'))	) 
  if (!IsEmptyValue(IsInserting = ParentDataset.State == dstInsert)) {
    var ds = Services.GetNewItemByUSI(IsInserting ? 
                'ds_RequestStockTypeMec' : 'ds_TypeMecDetail');
      if(!IsInserting) 
        ApplyDatasetFilter(ds, 'RequestStock2ID', ParentDataset('ID'),true);
      ds.Close();
      ds.Open();
      mdsTypeMecDetail.Dataset.Close();
      CopyMemoryDataset(ds, mdsTypeMecDetail.Dataset);
      if (Assigned(grdData))
      if(grdData.DatasetLink.Name != 'mdsTypeMecDetail')
      grdData.DatasetLink = mdsTypeMecDetail;
      ds.Close();
 
  }

где ds_TypeMecDetail - штатный датасет для данной детали,
ds_RequestStockTypeMec - датасет справочника, из которого подгружаются данные при Append
mdsTypeMecDetail - собственно меморидатасет, который и нужно заполнять в карточке
ParentDataset - датасет карточки редактирования записи, в которой и находится windowcontainer с гридом.

Проблема скорее всего тут:

grdData.DatasetLink = mdsTypeMecDetail;

Лучше всего сначала очистить, а затем заполнить свойство DatasetLink:

grdData.DatasetLink = System.EmptyValue;
grdData.DatasetLink = mdsTypeMecDetail;

А затем нужно открыть mds:

grdData.DatasetLink = System.EmptyValue;
grdData.DatasetLink = mdsTypeMecDetail;
grdData.DatasetLink.Dataset.Open();

И определить событие для DatasetLink(mdsTypeMecDetail): OnDatasetAfterOpen(Dataset), и уже внутри него заполнять mds. Тогда все будет корректно.

function dlDataOnDatasetAfterOpen(Dataset) {
Dataset.Append();
....
Dataset.Post();
}

Также не понял, почему используется GridAreaOnPrepare... Но тут нужно знать вашу бизнес задачу.

"Олейник Дмитрий" написал:Также не понял, почему используется GridAreaOnPrepare... Но тут нужно знать вашу бизнес задачу.

Исходно нужно реализовать "множественный выбор" (то есть все значения из справочника с галочками... очень похоже на деталь Доступ :smile: только в карточке редактирования).
Уже работающую деталь потребовалось положить в эдитвиндоу. Пытался "малой кровью" эту деталь использовать с подменой обычного датасета на меморидатасет.

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

http://www.community.terrasoft.ru/blogs/8462

Здорово получается, до инсерта/апдейта

grdData.DatasetLink.Dataset.Open();

вызывает memoryDatasetOnDatasetAfterOpen
а после апдейта .Open() уже игнорирует AfterOpen!

[quote="Олейник Дмитрий"]Ага, я когда-то чтото подобное делал с напоминаниями: открывается каточка детали "напоминания" какого либо раздела, там есть лукапное поле контакт, жмем на лупу и открывается multi_select_window - можно выбрать несоклько контактов, а затем при закрытии краточки - на деталь добавлялось столько записей, сколько выбрано было контактов.
Посмотрите, может быть поможет:

http://www.community.terrasoft.ru/blogs/8462[/quote]
Спасибо, Дмитрий! Попробую поразбираться.

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

Alex, а что значит Update?

Немного про мемориDS: это штука живет от Open() до Close(); Заполняется на OnDatasetAfterOpen(); После открытия датасета, можно позиционироваться на любой строке,и изменять любую ячейку:
Dataset.Edit();
Dataset.Post();
Все изменения грид перерисует самостоятельно.
Помните, что каждый рефреш, (Dataset.Close(), Dataset.Open()) вызывает перезаполнение датасета. Т.е. если вы не сохранили измененные данные куда то в таблицу БД, с которой заполняете датасет, то он заполнится старыми значениями.

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

Alex, а что значит Update?

Немного про мемориDS: это штука живет от Open() до Close(); Заполняется на OnDatasetAfterOpen(); После открытия датасета, можно позиционироваться на любой строке,и изменять любую ячейку:

Dataset.Edit();

Dataset.Post();

Все изменения грид перерисует самостоятельно.

Помните, что каждый рефреш, (Dataset.Close(), Dataset.Open()) вызывает перезаполнение датасета. Т.е. если вы не сохранили измененные данные куда то в таблицу БД, с которой заполняете датасет, то он заполнится старыми значениями.

С уважением,

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


В какой-то момент меморидатасет перестает реагировать на Dataset.Close() и Dataset.Open().
Пишу

grdData.DatasetLink = System.EmptyValue;
grdData.DatasetLink = mdsRStock2AccDivision;
grdData.DatasetLink.Dataset.Close();
SetAttribute(grdData.DatasetLink.Dataset, 'ParentWindow', Window);
if (Assigned(ParentDataset = GetAttribute(Window, 'ParentDataset'))	)		SetAttribute(grdData.DatasetLink.Dataset, 'ParentDataset', ParentDataset);
grdData.DatasetLink.Dataset.Open();

но ни
function mds_RStock2AccDivisionOnDatasetAfterOpen
ни
function mds_RStock2AccDivisionOnDatasetAfterClose

не срабатывают!

наконец нашел свой косяк:
в посте (записи из мемдатасета в реальный датасет) для мемдатасета делал DisableEvents(), а EnableEvents() забыл сделать.... теперь все обновляется!

Только почему-то если

Dataset.EnableEvents();
Dataset.Close();

то возникает ошибка:

TSObjectLibrary.MemoryDataset: Cannot focus a disabled or invisible window

а

Dataset.Close();
Dataset.EnableEvents();

ошибку не вызывает

Проверьте состояние датасета в момент Open() - быть может он уже в состоянии Open(), тогда функция не вызывается и события AfterOpen() не тригернутся.

Alex, да, бывает :)

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

Alex, да, бывает :)

С уважением,

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


Дмитрий, спасибо Вам за помощь!

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