Доброго времени суток, коллеги.

Система - TerrasoftCRM 3.3.2.245.

Имеется таблица со следующей структурой:

+------------+---------------+-------------+-------------+-------------+-------------+
| Контрагент | Ответственный | Показатель1 | Показатель2 | Показатель3 | Показатель4 |
+------------+---------------+-------------+-------------+-------------+-------------+

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

Вопрос такой: возможно ли использовать один компонент FilterBuilder для установки фильтров на два датасета сразу? 

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

Нравится

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

У FiltersBuilderControl есть свойство Mode с двумя возможными значениями. Может, то, что Вы хотите, можно получить, выставив fbmMultiDataset. Но как именно реализовать всю логику, нужно искать похожие примеры или экспериментировать. В стандартной конфигурации свойство Mode нигде не меняли, так что гарантии, что свойство сделано именно для этого, нет.

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

Я создаю шаблон счёт-фактуры, мне необходимо подсчитывать сумму с НДС и округлять сумму в каждой строке. На примере шаблонов других документов я хочу использовать OnDatasetCalcFields, который даёт возможность менять уже выбранные из БД значения. Например так:

var Value = Dataset.ValAsFloat('BasicTotalAmount');
ShowInformationDialog("Value before = " + Value);
var NDS = Value / 100 * 18;
ShowInformationDialog("NDS = " + NDS);
var Totally = System.Round(NDS + Value, 2);
Dataset.Values('BasicTotalAmount') = Value;

Проблема в том, что событие OnDatasetCalcFields не срабатывает в принципе. В других документах всё нормально. Пытался найти отличия от уже существующих Dataset-ов и шаблонов, но ни к чему не пришёл.
Как быть? Как заставить событие отрабатывать.

Нравится

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

Дмитрий, похожие вопросы рассматриваются в темах:

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

Да, действительно. Спасибо!

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

Добрый день!
Создал своё окно и вызываю его в коде, но оно отрывается без данных.
В чём может быть проблема?

Нравится

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

Как именно вы его открываете и какова вообще задача?

"Андросов Дмитрий" написал:

Как именно вы его открываете и какова вообще задача?

Открываю так:
WindowPrompt = GetSingleItemByCode('wnd_CategoryGiftArea');
WindowPrompt.ShowModal();

Мне нужно отобразить в собственном окне данные справочника.

Такое чувство, что окно базу не подключает.

если ваш реестр унаследован от базового и все остальное настроено правильно, то вам надо просто добавить Prepare() в эту функцию:

WindowPrompt = GetSingleItemByCode('wnd_CategoryGiftArea');
WindowPrompt.Prepare();
WindowPrompt.ShowModal();

"Андросов Дмитрий" написал:если ваш реестр унаследован от базового и все остальное настроено правильно, то вам надо просто добавить Prepare() в эту функцию:

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

"Егоров Руслан" написал:В обработчике этого события нужно, что-то писать?

если ваш реестр унаследован от базового и для dlData указан нужный датасет, то достаточно в OnPrepare написать

wnd_BaseGridAreaOnPrepare(Window);

"Андросов Дмитрий" написал:если ваш реестр унаследован от базового

А если нет?

тогда надо проинициализировать все (в т.ч. датасет) самому. Проще унаследовать :wink:

"Андросов Дмитрий" написал:Проще унаследовать

Т.е. указать значение в свойстве TemplateWindowUSI = wnd_BaseGridArea?
А после этого я могу удалить в окне не нужные мне элементы?

лучше использовать вот эту кнопку и, да, потом скрыть то, что не нужно

"Андросов Дмитрий" написал:потом скрыть то, что не нужно

можно только скрыть или удалить тоже можно?

"Егоров Руслан" написал:удалить тоже можно

не выйдет :smile:

"Андросов Дмитрий" написал:Проще унаследовать

Создал окно заново, но данных так и нет((
Где еще капать?

для начала прочитайте
http://www.community.terrasoft.ru/developer/advice/4576
а потом посмотрите, как реализованы существующие реестры

если не поможет, покажите скриншоты настроек окна и его скрипт

"Андросов Дмитрий" написал:для начала прочитайте
http://www.community.terrasoft.ru/developer/advice/4576
а потом посмотрите, как реализованы существующие реестры

если не поможет, покажите скриншоты настроек окна и его скрипт


Делал всё также.


а теперь еще события окна, пожалуйста

ПС. вы знаете о существовании окон выбора из справочника?

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

Открыть свое окно можно следующим образом:

var EditWindowUSI = 'wnd_OpportunityEdit';
var Attributes = GetNewDictionary();
Attributes.Add('RecordID', GUID_NULL);  // если не указываем RecordID, то открывается окно для добавления данных, если указываем, то запись с ID = RecordID открывается для редактирование
var DefaultValues = GetNewDictionary();  // значения по умолчанию
DefaultValues.Add('CustomerID', AccountID); 
ShowEditWindowEx(EditWindowUSI, Attributes, DefaultValues);

"Безродный Андрей" написал:Здравствуйте!

Открыть свое окно можно следующим образом:

Это тоже пробовал. Та же самая ситуация, данных нет.

"Андросов Дмитрий" написал:ПС. вы знаете о существовании окон выбора из справочника?

Где можно про это почитать?

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

Вот:

Сделал через вызов окна "SelectData".
Но мне бы хотелось узнать, как можно подгрузить данные в своё окно?

Сделайте dlData.Dataset.Open() на OnPrepare()

"Олейник Дмитрий" написал:Сделайте dlData.Dataset.Open() на OnPrepare()

Сделал, не подгружает.

Здравствуйте, Руслан!

Прикрепите все используемые Вами сервисы и сообщите точную версию.

Будем воспроизводить.

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

Добрый день

В окне есть 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 окна с В.

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

Господа

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

В не визуальные компоненты окна - добавил необходимый набор данных, на форме разместил компонент LookupDataControl, для свойства DatasetLink - указал добавленный мной набор данных. Но при установке свойства DataFieldName - в журнал выбрасывается ошибка
"Невозможно установить имя поля "FieldName" для компонента "LookupDataControl""
В наборе данный ключевое поле, и первичное поле для отображения установлены.

В чём может быть причина ошибки?

С уважением
Егор

Нравится

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

Хотел использовать простой LookupControl, но при открытии окна выходит ошибка иного рода.

0x8000ffff - TSObjectLibrary.DBDataset: Ошибка открытия источника данных "ds_OrderGiftsList".

Оригинальное сообщение об ошибке: All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists

Егор, что представляет собой sq_OrderGiftsList, он содержит union-ы?
Если содержит, проверьте чтобы все union содержали одинаковое количество колонок с одинаковым набором свойств.

SELECT
	[ID],
	[Name],
	[LotID],
	[LotName],
	[IsJewel],
	[IsEvent],
	[GiftID],
	[GiftName],
	[AmountFrom],
	[GiftTypeID],
	[GiftDescription]
FROM
	(
    SELECT
  	  '{00000000-0000-0000-0000-000000000002}' AS [ID],
  	  NULL AS [Name],
  	  [tbl_LotInGift].[LotID] AS [LotID],
  	  [tbl_Lot].[Name] AS [LotName],
  	  [tbl_Lot].[IsJewel] AS [IsJewel],
  	  [tbl_Lot].[IsEvent] AS [IsEvent],
  	  [tbl_Gift].[ID] AS [GiftID],
  	  [tbl_Gift].[Name] AS [GiftName],
  	  [tbl_Gift].[AmountFrom] AS [AmountFrom],
  	  [tbl_Gift].[TypeID] AS [GiftTypeID],
  	  NULL AS [GiftDescription]
    FROM
	    [dbo].[tbl_Gift] AS [tbl_Gift]
    INNER JOIN
	    [dbo].[tbl_LotInGift] AS [tbl_LotInGift] ON [tbl_LotInGift].[GiftID] = [tbl_Gift].[ID]
    LEFT OUTER JOIN
	    [dbo].[tbl_Lot] AS [tbl_Lot] ON [tbl_Lot].[ID] = [tbl_LotInGift].[LotID]
    LEFT OUTER JOIN
	    [dbo].[tbl_SaleSource] AS [tbl_SaleSource] ON [tbl_SaleSource].[ChannelID] = [tbl_Gift].[ChannelID]
    WHERE([tbl_Gift].[TypeID] = :gtOrderNumber AND
	    :Date BETWEEN [tbl_Gift].[DateFrom] AND [tbl_Gift].[DateTo] AND
	    (([tbl_Gift].[SourceID] IS NULL AND
	    [tbl_Gift].[ChannelID] IS NULL) OR
	    ([tbl_Gift].[SourceID] IS NULL AND
	    [tbl_SaleSource].[ID] = :SourceID) OR
	    ([tbl_Gift].[SourceID] = :SourceID)) AND
	    [tbl_Lot].[StatusID] IN (:LotStatusIsOpen) AND
	    [tbl_Gift].[StateID] = :gfstActive AND
	    dbo.tsf_GetIsOrderNumberGiftAppllicable(:OrderNumber, tbl_Gift.OrderNumberPeriod,
      tbl_Gift.OrderNumberMaxCount, tbl_Gift.OrderNumberStartValue, tbl_Gift.OrderNumberCount)   = 1)
UNION ALL
SELECT
	N'{00000000-0000-0000-0000-000000000001}' AS [ID],
	NULL AS [Name],
	[tbl_LotInGift].[LotID] AS [LotID],
	[tbl_Lot].[Name] AS [LotName],
	[tbl_Lot].[IsJewel] AS [IsJewel],
	[tbl_Lot].[IsEvent] AS [IsEvent],
	[tbl_Gift].[ID] AS [GiftID],
	[tbl_Gift].[Name] AS [GiftName],
	[tbl_Gift].[AmountFrom] AS [AmountFrom],
	[tbl_Gift].[TypeID] AS [GiftTypeID],
	SetLot1Code + ';' + SetLot2Code AS [GiftDescription]
FROM
	[dbo].[tbl_Gift] AS [tbl_Gift]
INNER JOIN
	[dbo].[tbl_LotInGift] AS [tbl_LotInGift] ON [tbl_LotInGift].[GiftID] = [tbl_Gift].[ID]
LEFT OUTER JOIN
	[dbo].[tbl_Lot] AS [tbl_Lot] ON [tbl_Lot].[ID] = [tbl_LotInGift].[LotID]
LEFT OUTER JOIN
	[dbo].[tbl_SaleSource] AS [tbl_SaleSource] ON [tbl_SaleSource].[ChannelID] = [tbl_Gift].[ChannelID]
WHERE([tbl_Gift].[TypeID] = :gtLotSet AND
	:Date BETWEEN [tbl_Gift].[DateFrom] AND [tbl_Gift].[DateTo] AND
	(([tbl_Gift].[SourceID] IS NULL AND
	[tbl_Gift].[ChannelID] IS NULL) OR
	([tbl_Gift].[SourceID] IS NULL AND
	[tbl_SaleSource].[ID] = :SourceID) OR
	([tbl_Gift].[SourceID] = :SourceID)) AND
	[tbl_Gift].[StateID] = :gfstActive AND
	dbo.tsf_GetIsLotSetGiftAppllicable(:OrderID, tbl_Gift.ID) = 1 AND
	[tbl_Lot].[StatusID] IN (:LotStatusIsOpen))
UNION ALL
SELECT
	'{00000000-0000-0000-0000-000000000000}' AS [ID],
	NULL AS [Name],
	[tbl_LotInGift].[LotID] AS [LotID],
	[tbl_Lot].[Name] AS [LotName],
	[tbl_Lot].[IsJewel] AS [IsJewel],
	[tbl_Lot].[IsEvent] AS [IsEvent],
	[tbl_Gift].[ID] AS [GiftID],
	[tbl_Gift].[Name] AS [GiftName],
	[tbl_Gift].[AmountFrom] AS [AmountFrom],
	[tbl_Gift].[TypeID] AS [TypeID],
	NULL AS [GiftDescription]
FROM
	[dbo].[tbl_Gift] AS [tbl_Gift]
INNER JOIN
	[dbo].[tbl_LotInGift] AS [tbl_LotInGift] ON [tbl_LotInGift].[GiftID] = [tbl_Gift].[ID]
LEFT OUTER JOIN
	[dbo].[tbl_Lot] AS [tbl_Lot] ON [tbl_Lot].[ID] = [tbl_LotInGift].[LotID]
LEFT OUTER JOIN
	[dbo].[tbl_SaleSource] AS [tbl_SaleSource] ON [tbl_SaleSource].[ChannelID] = [tbl_Gift].[ChannelID]
WHERE([tbl_Gift].[TypeID] = :gtOrderAmount AND
	:Date BETWEEN [tbl_Gift].[DateFrom] AND [tbl_Gift].[DateTo] AND
	(([tbl_Gift].[SourceID] IS NULL AND
	[tbl_Gift].[ChannelID] IS NULL) OR
	([tbl_Gift].[SourceID] IS NULL AND
	[tbl_SaleSource].[ID] = :SourceID) OR
	([tbl_Gift].[SourceID] = :SourceID)) AND
	[tbl_Lot].[StatusID] IN (:LotStatusIsOpen) AND
	[tbl_Gift].[StateID] = :gfstActive AND
 
	(SELECT
		SUM([tbl_Partable].[Amount]) AS [Amount]
	FROM
		[dbo].[tbl_Orders] AS [tbl_Orders]
	LEFT OUTER JOIN
		[dbo].[tbl_Partable] AS [tbl_Partable] ON [tbl_Partable].[OrdersID] = [tbl_Orders].[ID]
	WHERE([tbl_Orders].[ID] = :OrderID AND
		[tbl_Partable].[default] = :TRUE AND
		[tbl_Partable].[IsGift] = :False)) BETWEEN [tbl_Gift].[AmountFrom] AND [tbl_Gift].[AmountTo])
UNION ALL
SELECT
	'{00000000-0000-0000-0000-000000000004}' AS [ID],
	NULL AS [Name],
	[tbl_LotInGift].[LotID] AS [LotID],
	[tbl_Lot].[Name] AS [LotName],
	[tbl_Lot].[IsJewel] AS [IsJewel],
	[tbl_Lot].[IsEvent] AS [IsEvent],
	[tbl_Gift].[ID] AS [GiftID],
	[tbl_Gift].[Name] AS [GiftName],
	[tbl_Gift].[AmountFrom] AS [AmountFrom],
	[tbl_Gift].[TypeID] AS [TypeID],
	NULL AS [GiftDescription]
FROM
	[dbo].[tbl_Gift] AS [tbl_Gift]
INNER JOIN
	[dbo].[tbl_LotInGift] AS [tbl_LotInGift] ON [tbl_LotInGift].[GiftID] = [tbl_Gift].[ID]
LEFT OUTER JOIN
	[dbo].[tbl_Lot] AS [tbl_Lot] ON [tbl_Lot].[ID] = [tbl_LotInGift].[LotID]
LEFT OUTER JOIN
	[dbo].[tbl_SaleSource] AS [tbl_SaleSource] ON [tbl_SaleSource].[ChannelID] = [tbl_Gift].[ChannelID]
WHERE([tbl_Gift].[TypeID] = :gtClientLoyalty AND
	:Date BETWEEN [tbl_Gift].[DateFrom] AND [tbl_Gift].[DateTo] AND
	(([tbl_Gift].[SourceID] IS NULL AND
	[tbl_Gift].[ChannelID] IS NULL) OR
	([tbl_Gift].[SourceID] IS NULL AND
	[tbl_SaleSource].[ID] = :SourceID) OR
	([tbl_Gift].[SourceID] = :SourceID) OR
	[tbl_Lot].[StatusID] IN (:LotStatusIsOpen) OR
	[tbl_Gift].[StateID] = :gfstActive) AND
	[tbl_Gift].[LoyaltyID] = :LoyaltyID)
UNION ALL
SELECT
	[tbl_Partable].[LotsID] AS [ID],
	[ReasonLot].[Name] AS [Name],
	[tbl_LotInGift].[LotID] AS [LotID],
	[tbl_Lot].[Name] AS [LotName],
	[tbl_Lot].[IsJewel] AS [IsJewel],
	[tbl_Lot].[IsEvent] AS [IsEvent],
	[tbl_Gift].[ID] AS [GiftID],
	[tbl_Gift].[Name] AS [GiftName],
	[tbl_Gift].[AmountFrom] AS [AmountFrom],
	[tbl_Gift].[TypeID] AS [TypeID],
	cast([tbl_Partable].[LotsID] as nvarchar(40)) AS [GiftDescription]
FROM
	[dbo].[tbl_Orders] AS [tbl_Orders]
LEFT OUTER JOIN
	[dbo].[tbl_Partable] AS [tbl_Partable] ON [tbl_Partable].[OrdersID] = [tbl_Orders].[ID]
LEFT OUTER JOIN
	[dbo].[tbl_Gift] AS [tbl_Gift] ON [tbl_Gift].[LotID] = [tbl_Partable].[LotsID]
LEFT OUTER JOIN
	[dbo].[tbl_LotInGift] AS [tbl_LotInGift] ON [tbl_LotInGift].[GiftID] = [tbl_Gift].[ID]
LEFT OUTER JOIN
	[dbo].[tbl_Lot] AS [tbl_Lot] ON [tbl_Lot].[ID] = [tbl_LotInGift].[LotID]
LEFT OUTER JOIN
	[dbo].[tbl_SaleSource] AS [tbl_SaleSource] ON [tbl_SaleSource].[ID] = [tbl_Orders].[SourceID]
LEFT OUTER JOIN
	[dbo].[tbl_Lot] AS [ReasonLot] ON [ReasonLot].[ID] = [tbl_Partable].[LotsID]
WHERE([tbl_Gift].[TypeID] = :gtOrderQuantity AND
	:Date BETWEEN [tbl_Gift].[DateFrom] AND [tbl_Gift].[DateTo] AND
	(([tbl_Gift].[SourceID] IS NULL AND
	[tbl_Gift].[ChannelID] IS NULL) OR
	([tbl_Gift].[SourceID] IS NULL AND
	[tbl_Gift].[ChannelID] = [tbl_SaleSource].[ChannelID]) OR
	([tbl_Gift].[SourceID] = :SourceID)) AND
	[tbl_Gift].[StateID] = :gfstActive AND
	[tbl_Orders].[ID] = :OrderID AND
	[tbl_Partable].[default] = :TRUE AND
	[tbl_Partable].[IsGift] = :False AND
	[tbl_Lot].[StatusID] IN (:LotStatusIsOpen) AND
	0 = 0) 
GROUP BY
        [tbl_Gift].[ID],
        [tbl_Gift].[Name],
       	[ReasonLot].[Name],
        [tbl_LotInGift].[ID],        
	[tbl_Partable].[LotsID],
	[tbl_LotInGift].[LotID],
	[tbl_Lot].[Name],
	[tbl_Lot].[IsJewel],
	[tbl_Lot].[IsEvent],
	[tbl_Gift].[QuantityFrom],
	[tbl_Gift].[QuantityTo],
	[tbl_Gift].[TypeID],
	[tbl_Gift].[AmountFrom]
 
HAVING COUNT([tbl_Partable].[ID]) BETWEEN [tbl_Gift].[QuantityFrom]   AND [tbl_Gift].[QuantityTo]
 
) AS [U] ORDER BY [ID] --	)) AS [U]

Вот такая страшная штука.
Этот sq был создан давно, и каким то образом функционирует в системе.
Но как только я захотел получить набор данных на его основании, он выдал ошибку.

Yegor, первое что бросается в глаза - заголовок 10-й колонки в первых 3-х подзапросах (union) GiftTypeID, а в последующих TypeID, что некорректно.
Вам нужно изменить заголовки и свойства колонок в запросе таким образом, чтобы они были одинаковы во всех union-х.

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

Salud los colegas!

Товарищи, продолжаю погружаться в дебри Terrasoft, собирая все грабли на этом тернистом пути.
Играя с SDK, решил налить Dataset, несколькими записями, и посмотреть на метод Append() в действии.
Дано:
tbl + sq + ds
scr

function Main() {
    var Dataset = Services.GetNewItemByUSI('ds_DBDataset');
    Dataset.Open();
    var String = 'Some text ';
    var i;
    for (i = 0; i 5; i++) {
        Dataset.Append();
        Dataset('String') = String + i;
        Dataset.Post();
    }
    MessageBox(Dataset.RecordCount);
    Dataset.Close();

Найти:
В результате выполнения скрипта имею ошибку Terrasoft - Dataset not in edit or insert mode (Dataset.Edit(); - совершенно иная конструкция) Вот здесь шаблоны рушатся.
Возможно я не верно понимаю логику инструкции Append().

В ожидании луча света, и с уважением
Ваш коллега.

Нравится

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

Yegor, проверила Ваш код - работает корректно.
Только подправила

Dataset.RecordCount

на

Dataset.RecordsCount

Тестировала на версии 3.4.1
Результаты тестирования во вложенных скриншотах (1 - до записи в БД, после записи БД).

На какой версии Вы работаете?

У меня тоже работает, не считая того, что вместо MessageBox надо писать

System.MessageDialog('Hello world', mdtInformation, mdbOK, 0);

или обёртку из scr_WindowUtils

ShowInformationDialog('Hello world')

"Бондарь Наталия" написал:На какой версии Вы работаете?

Версия - 3.3.2.222
В строке

Dataset('String') = String + i;

ругается.
Я задумываться начинаю, может собака глубже зарыта, и своими неопытными ручками я tbl + sq + ds не по человечески связал :confused:?
Здесь всё просто (на сколько понял) Одна таблица с полем String (остальные по дефолту). Select Query завязанный на таблицу с селектами по ID и String. Ну и Dataset завязанный на Select Query с ключевым полем ID.
Ударьте по рукам пожалуйста если что не так :neutral:

Александр, прошу Вас, дабы полностью разрушить мои стереотипы пояснить моменты по поводу окон сообщений.
Привычного alert() декларированного в ECMAScript я не обнаружил. Случайно наткнувшись на MessageBox('Text'), ужаснулся и стал ностальгировать о Delphi (синтаксис идентичен)

  1. 1. Данные методы являются глобальными встроенными методами Terrasoft ( кроме ShowInformationDialog('Text') явно не глобальный :smile:)?
  2. 2. И в чём принципиальная разница каждого? Только в гибкости настроек вывода (доп. кнопки, выбор иконки и т.п.) или что-то ещё?

Егор, покажите скриншоты всех трёх сервисов.

Идеология конфигурации Terrasoft 3.X такова, что методы встроенных глобальных объектов стараются использовать минимально. Взамен им в скриптах-библиотеках scr_Utils, scr_WindowUtils и других написаны функции-обёртки, часто с дополнительными возможностями или скрытием ненужных обычно параметров. Например, одному методу System.MessageDialog с кучей параметров соответствует семейство ShowInformationDialog, ShowErrorDialog, ShowWarningDialog с одним параметром — текстом сообщения.

Аналогично, вместо Services.GetNewItemByUSI лучше использовать функцию GetSingleItemByCode (она уже есть в какой-то библиотеке), не создающую лишних сущностей без необходимости.

"Зверев Александр" написал:Егор, покажите скриншоты всех трёх сервисов.




Спасибо, уяснил момент.
Только под резюмирую - исторически сложилось, что MessageBox('Text') не является правилом хорошего тона, верно?

Метод MessageBox является одной из обёрток, о которых писал Александр. Его использование вполне уместно.

Ошибка говорит о том, что свойство Dataset.State != dstInsert(dstEdit).
Это значит, что метод

Dataset.Append();

не отработал.

Поставьте галочку в сервисе датасета "Добавление", а также определите первичное поле для отображения.

Hallelujah

Дмитрий, благодарю! +1 к Dataset :smile:
Всех благодарю за уделённое внимание!
С уважением Ваш коллега

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

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

Если в событии OnPrepare окна задать айди справочника кодом, скажем, для значения по умолчанию
поля TypeID

dlData.Dataset('TypeID') = '{2400133D-b146-46C3-83E7-2C0DCDECCBA5}';

Обратите внимание на маленькую букву в индексе. Результатом подобного кода станет следующее:

При открытии карточки компонент "Справочник" корректно отработает запрос и покажет заполненное из справочника поле. После сохранения он запишет в базу этот ID с маленькой буквой и если карточку этого объекта открыть, то запрос с некорректным ID уже отрабатывается другим компонентом, предполагаю, что классом Dataset и он уже такой join связать не сможет - результатом будет null в поле отображения и как результат пустое поле справочника в карточке

Нравится

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

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

Константин, не сумел воспроизвести описанное на 153-й сборке.
Приложение помещает в базу идентификатор приведенный к верхнему регистру. Возможно, Вам стоит запросить последние бинарные файлы.

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

Что нужно сделать, что бы DataGrid уже привязанный к DataSet даталинка отобразил данные. В любом месте проинициализировать DataSet и DataGrid автоматом все отобразит(колонки настроены)?

P.S. вопрос решен, действительно нужно просто правильно DataSet инициализировать

Нравится

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

На OnPrepare грида пропишите

scr_BaseGridArea.wnd_BaseGridAreaOnPrepare(Window);

И автоматом все будет отображать.

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

Где задаётся обработчик событий элементов карточки редактирования сервиса, в случае, если в свойствах невизуальных компонентов этого сервиса явно не задан Dataset?
Попробовал добавить обработчик dlDataOnDatasetDataChange(DataField) на событие OnDatasetDataChange невизуального компонента dlData - не работает (обработчик не вызывается).

Нравится

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

дело в том, что

function dlDataOnDatasetDataChange(DataField)

вызывается по полю, а чтобы у вас было поле, вам нужен датасет :smile:

Ок. Получается, обязательно нужно привязывать датасет?

Алексей, если Вам нужно событие OnDatasetDataChange - то разумеется у Вас должен быть датасет, чтобы сработало это событие.
Если он явно не указан в дизайнере окна, скорее всего он инициализируется на OnPrepare событии окна:

dlData.Dataset = Services.GetNewItemByUSI('ds_Account');

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

Я добавил в обработчик события OnPrepare следующую строку:

dlData.Dataset = Services.GetNewItemByUSI('ds_Offering');

К сожалению, всё осталось по-прежнему, обработчик dlDataOnDatasetDataChange(DataField) на событие OnDatasetDataChange невизуального компонента dlData - не вызывается.

у вас это свойство ведь заполнено?

"Андросов Дмитрий" написал:

Дмитрий,

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


Дмитрий, нет, сначала срабатывают обработчики события DataLink'a, если конечно датасет ему присвоен, и обработчики событий определены.
Затем срабатывают события самого сервиса датасета.
Они - независимы.

Алексей, я так и не понял, у Вас получилось добиться отработки события?

Этой строчкой вы пробуете впихнуть весь датасет в карточку

dlData.Dataset = Services.GetNewItemByUSI('ds_Offering');

Указать датасет невизуально довольно тонкий процесс (это означает вы хотите сделать один грид и одну карточку редактирования для нескольких похожих сущностей, иначе легче указать датасет сразу), посмотрите в качестве примера окна wnd_OfferingDetailEdit и wnd_OfferingsDetailTreeArea и их скрипты.
Эти окна предназначены для продуктов в счетах, документах и договорах. Можно заметить, что там привязка датасета идет не в карточке, а перед открытием карточки, т.е. в гриде.

"Олейник Дмитрий" написал: Алексей, я так и не понял, у Вас получилось добиться отработки события?
Дмитрий, нет, не получилось.

Давайте, я опишу ситуацию поподробнее.

Я создал новую пользовательскую карточку редактирования.
Вот такую: http://www.community.terrasoft.ru/forum/topic/9879#comment-44071
Сейчас мне нужно блокировать/разблокировать соответствующие поля ввода (поля, определяющие размер скидки) в зависимости от выбранного "радиобуттона" (относительное или абсолютное значение скидки).

Формы раздела (гриды, воркспейсы, карточки редактирования), в котором находится новый воркспейс, не имеют явного задания в свойствах невизуальных компонентов Dataset-ов.
Моя новая пользовательская форма (карточка редактирования wnd_SetDiscountInInvoice) также не имеет явной привязки датасета.

Объясните, пожалуйста, как обрабатывать события?
Вариант "поздней" привязки датасета по событию OnPrepare предложенный Дмитрием Олейником (http://www.community.terrasoft.ru/forum/topic/10032#comment-44333) "не прокатил".

а у вас к "радиобуттону" поле датасета привязано? ну так, проверьте на всякий случай .... :lol:

у контролов есть свои события, которые я вам и предлагаю обрабатывать

Алексей, я так предполагаю, что датасет в Вашей форме вообще не нужен, а на кнопку ОК у вас отрабатывается какой-то скрипт, да?
Так почему бы не повесить блокировку/разблокировку полей на события OnClick на радиобатонах?

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


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

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

Алексей, я так предполагаю, что датасет в Вашей форме вообще не нужен, а на кнопку ОК у вас отрабатывается какой-то скрипт, да?

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


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

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

"Алейник Алексей Вадимович" написал:или это ирония?

это ирония

В общем, "радиобатон" (батон? радио? брр) radiobutton нельзя привязать к полю датасета\даталинка, поэтому, что бы вы с ним ни делали, событие dlDataOnDatasetDataChange, как и любые другие события для dlData, не произойдет.

Поэтому воспользуйтесь советом Александра Сазанова:

"Сазанов Александр Владимирович" написал:повесить блокировку/разблокировку полей на события OnClick на радиобатонах

Спасибо всем! Всё замечательно получилось!:twisted:

"Андросов Дмитрий" написал:

В общем, "радиобатон" (батон? радио? брр)


радиобатон

"Андросов Дмитрий" написал:В общем, "радиобатон" (батон? радио? брр)

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

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

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

поле отчёта: Memo5
датасет: dsReportOfferingMovementRemain
Memo (значение) поля Memo5: [Sum()]

Нравится

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

Если поле с sum убрать и работает, то предположу что sum не нравиться null в данных, в выборку добавить ISNULL(xxxxxx,0). Хотя текст об неоткрытом датасете.

"Борисов Михаил Евгеньевич" написал:

"причём только для одного определённого склада и только для одного определённого типа продукции" - если отчет в принципе работает, то предположу что sum не нравиться null в данных, в выборку добавить ISNULL(xxxxxx,0).


Михаил, вполне возможно, что вы правы, ранее добавлялось поле артикул, но ещё не все продукты его имеют. Если не сложно, можно поподробнее? Это добавить в селектквери? Если да, то куда именно и как?

В sq_ сервис добавить новое поле select, в нем написать ISNULL(Quantity,0) если БД MSSQL, в соотвествующем сервисе ds_ добавить числовое поле и указанть созданое поле в sq_, обновить отчет, вместо Quantity указать новое поле. Все это стоит делать только если отчет работает без этого поля. Как вариант поставить туда max например, если не заработает то не в данных проблема.

Алексей, попробуйте подменить

[Sum(<dsReportOfferingMovementRemain."Quantity">)] 

на

[SUM(<dsReportOfferingMovementRemain."Quantity">,DetailData1)]

будет возникать ошибка?

"Бондарь Наталия" написал:

Алексей, попробуйте подменить

[Sum(<dsReportOfferingMovementRemain."Quantity">)] на [SUM(<dsReportOfferingMovementRemain."Quantity">,DetailData1)] будет возникать ошибка?


не помогло,
"Борисов Михаил Евгеньевич" написал:

В sq_ сервис добавить новое поле select, в нем написать ISNULL(Quantity,0) если БД MSSQL, в соотвествующем сервисе ds_ добавить числовое поле и указанть созданое поле в sq_, обновить отчет, вместо Quantity указать новое поле. Все это стоит делать только если отчет работает без этого поля. Как вариант поставить туда max например, если не заработает то не в данных проблема.


я так понимаю, ISNULL() - это вот эта функция?: http://msdn.microsoft.com/ru-ru/library/ms184325.aspx
в нем написать ISNULL(Quantity,0)
Куда в нем это написать? где написать?
что писать в каждом из этих полей?
Я правильно понимаю, что смысл в том, чтобы преобразовывать NULL в "0"?
Мне не понятно, как с помощью конструктора sq_ это сделать. Простите, но если не сложно, можно ещё подробнее, или хотя бы какую-нибудь ссылочку для понимания происходящего

А обязательно ли это делать через sq?
Создайте в датасете вычисляемое поле ('FieldX'), и на OnDatasetCalcFields пропишите

if (Dataset('Quantity')==null) Dataset('FieldX') = 0;
else Dataset('FieldX') = Dataset('Quantity');

И используйте в отчете это поле.

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

А обязательно ли это делать через sq?

Создайте в датасете вычисляемое поле ('FieldX'), и на OnDatasetCalcFields пропишите

if (Dataset('Quantity')==null) Dataset('FieldX') = 0;

else Dataset('FieldX') = Dataset('Quantity');

И используйте в отчете это поле.


Попробовал, пишет ошибку: "Источник данных "%s" не открыт"
Не помогло

А мы вообще туда копаем? Глянул на рисунок. Хоть немного непонятно, но
В MasterData датасет ...RemainHeader, а поле склад относится к датасету ...MovementRemain, а используете в MasterData.
Я думаю вот оно.

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

А мы вообще туда копаем? Глянул на рисунок. Хоть немного непонятно, но

В MasterData датасет ...RemainHeader, а поле склад относится к датасету ...MovementRemain, а используете в MasterData.

Я думаю вот оно.


Ок, Вы были правы я там исправил, но по-прежнему выскакивает та же ошибка.

Алексей, согласно телефонной договоренности направьте, пожалуйста, в техническую поддержку резервную копию БД.

"Бондарь Наталия" написал:

Алексей, согласно телефонной договоренности направьте, пожалуйста, в техническую поддержку резервную копию БД.


Направлена

Сервис отчета с исправлениями во вложении.

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