Добрый день!

После недавнего обновления Win10 (KB4056892), в Terrasoft 3.4.0.130 перестал отображаться пользователь в верхней части окна, отсутствуют напоминания и при переходе во вкладку Сделки появляется ошибка(та, что на скриншоте). Возможно кто-то сталкивался? Если обновление удалить все работает.

Изображение удалено.

Нравится

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

Этот сбой возникает на Windows 10 после прихода обновления KB4074588, которое ломает в Terrasoft пользовательские настройки. А этот раздел одну из них при открытии проверяет, как и механизм напоминаний.

Для восстановления нормальной работы нужно либо удалить из Windows это обновление KB4074588, либо запускать Terrasoft к компьютеров не под Windows 10. В руководстве администратора Terrasoft 3.4.0 указаны как поддерживаемые Windows XP, Windows Server 2003, Windows Vista, Windows Server 2008 и Windows 7.

Для быстрого перехода на другой компьютер достаточно просто целиком скопировать папку Terrasoft, а затем запустить в окне логина нажать лупу и так же настроить доступ в базу. Первый запуск TSClient.exe на новом месте нужно произвести под администратором Windows, нажав правую кнопку мыши на файле.

Зверев Александр,

Большое спасибо

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

Добрый день!

В один прекрасный день перестал запускаться Terrasoft версия 3.3.2.102. Т.е. при запуске TSClient.exe ничего не происходило, что от обычного пользователя, что от имени администратора. Решил я его переустановить. В итоге установщик доходит до регистрации файлов и выскакивает ошибка Runtime error 216 at 40005CDE(установщик запускался от имени администратора).

ОС Windows 10 1709 сборка 16299.125

В журнале появилась ошибка :

Имя сбойного приложения: regsvr32.exe, версия: 10.0.16299.15, метка времени: 0x43953aae

Имя сбойного модуля: rtl70.bpl, версия: 7.0.8.1, метка времени: 0x2a425e19

Код исключения: 0xc0000005

Смещение ошибки: 0x00005cde

Идентификатор сбойного процесса: 0x1fdc

Время запуска сбойного приложения: 0x01d3af8901dc89a3

Путь сбойного приложения: C:\WINDOWS\SysWOW64\regsvr32.exe

Путь сбойного модуля: C:\Program Files (x86)\Terrasoft\Bin\rtl70.bpl

Идентификатор отчета: 32e0ab5e-79e8-4098-a84a-74946647ac6a

 

Нравится

2 комментария
Вопрос

После переустановки Win7 на Win10 Террасофт просто отказывается запускаться. На 7 работает прекрасно. Если ли возможность обновить клиент на машинах с 10? На форуме полазил, но явного ответа что-то не увидел. Ткните плз...

Изображение удалено.

 

Нравится

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

Перед новым годом Microsoft что-то поменяли в обновлении Windows 10 и старые сборки 3.3.1 и 3.3.2 перестали работать. Помогает обновление файлов Terrasoft до последних 3.3.1.186 и 3.3.2.313.

Зверев Александр,

+ в карму и большое спасибо 

Добрый день!

Дистрибутивы английской и русской сборок  можно скачать по этой ссылке.

Для обновления с 3.3.2.245 на 3.3.2.313 Вам нужно заменить все содержимое папок [Bin], [Res], [Settings] (на всех пк, где используется система, если их несколько).

Добрый день, Валерий!

Спасибо за пакет обновления. Поставил, проверил. Работает.

А есть ли смысл обновлять до версии 3.4?

Добрый день!

Всегда рады помочь!

Что касается обновления, то данная процедура требует перезаказа лицензий, что обозначает, что на Вашем Customer ID необходимо наличие данных лицензий (3.4.0). Данную возможность Вам нужно предварительно обсудить с менеджером, ответственным по Вашей компании. Для решения данного вопроса рекомендуем обратится на электронный адрес технической поддержки support@bpmonline.com с указанием актуальных контактных данных для инициализации Вашей компании (или можно просто свой CID) и ответственный менеджер свяжется с Вами для обсуждения данного вопроса. Также, вполне вероятно, Вас может заинтересовать переход на версию 7.Х, которая в своем арсенале имеет огромный ряд преимуществ по сравнению с 3.Х. Более подробно узнать о возможностях системы Вы можете на нашем сайте https://www.terrasoft.ru/crm-products, а также подробно ознакомиться с функциональностью на академии https://academy.terrasoft.ru

Адасюк Валерий Викторович,

Добрый день, Валерий!

Такой вопрос - можно ли получить полноценный установщик для версии 3.3.2.313? просто если вдруг компьютер сломается, и будет принято решение его заменить на новый с ОС Windows 10, то нужен будет полноценный установщик, так как версия 3.3.2.245 после последних обновлений не только не запускается, но и не устанавливается корректно.

Добрый день.

Для 313 есть либо этот архив, либо установщик для продукта XRM. В принципе, разница только в названии ярлыков и бекапе пустой базы, которая идёт в комплекте. Если брать Вашу существующую базу, то с ней тоже заработает.

Установщик для CRM есть для предыдущей 312. Думаю, он тоже подойдёт.

Обратите внимание, при установке и при первом запуске нужно запускать под администратором Windows (правой кнопкой на exe-файле). Возможно, таким образом и из Вашего старого дистрибутива установится.

По поводу обновления до 3.4. Всё, что написал Валерий верно, но лучше будет не на 3.4.0, а на 3.4.1. Под Windows 10 после обновления KB4074588 даже в последней 3.3.2.313 могут наблюдаться сбои, которых в 3.4.1 не будет.

Так что, если есть возможность, лучше не использовать Terrasoft 3.3.2 под Windows 10, либо удалять это обновление.

Зверев Александр,

Добрый день, Александр!

Спасибо большое за помощь. 

Похожая проблема с 3.3.1.185 и Windows 10 1809. Можно получить бинарники версии 3.3.1.186 (или какие там последние в версии 3.3.1)? KB4074588 отменить возможности нет.

Под 3.3.1 обновление до последней сборки не полностью поможет, нужен переход на 3.4.1 с покупкой новых лицензий.

Чёт мне не охота новые лицензии покупать. Совсем. Дайте 3.3.1.186 последний убедиться самому.

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

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

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

Имеется TerrasoftCRM 3.3.2.245.

В отчетах FastReport я новичок, поэтому вопрос может показаться глупым: как настроить связь между двумя наборами данных? Свойство MasterDataset в наборе данных я нашел, а как указать состав полей по которым будет выполнятся связывание? По одинаковым именам полей в родительском и дочернем наборах данных связь по всей видимости тоже не устанавливается...

 

Нравится

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

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

При нажатии кнопки "OK" документа нужно делать некоторую валидацию значения конкретного поля.

Как узнать значение конкретного поля документа до сохранения записи в базе данных ?

Нравится

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

Логика до момента сохранения подключается на событие BeforePost. Оно есть и на датасете, и на источнике данных в карточке. Внутри этого метода поля доступны через Dataset.Values('MyFieldName'), как и обычно.

В обоих случаях в метод передаётся параметр DoPost. И если проверка отрицательная, чтобы отменить сохранение пишут: DoPost.Value = false; (обратите внимание на синтаксис).

Также можно прямо переопределить обработчик btnOKOnClick, написать там логику проверки и если условия выполнены — запустить базовый обработчик командой scr_BaseDBEdit.btnOKOnClick(Control);

 

Спасобо Александр.

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

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

Есть TerrasoftCRM 3.3.2.245.

При выборе значения фильтра из FilterBuilderControl вызывается стандартное окно wnd_MultiSelectData. Можно ли заменить его на свое? По аналогии с заданием свойства LookupWindowUSI в LookupControl.

Нравится

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

У компонента фильтра есть событие OnFiltersBuilderValueSelect. Возможно, логику можно прописать в его обработчике.

В конфигурации готовых примеров нет, но в 3.4.1 похожее событие OnFiltersBuilderItemSelect в скрипте wnd_IWTGraphWizardScript окна настройки графика переопределяется и в функции fbcFilterOnFiltersBuilderItemSelect задаётся своё окно:

function fbcFilterOnFiltersBuilderItemSelect(FilterBuilderControl, FiltersBuilderItem, AX, AY, DoHandled) {
	DoHandled.Value = false;
	var FiltersBuilder = FilterBuilderControl.FiltersBuilder;
	if (!GraphWizard.CustomDataset) {
		return;
	}
	var FBItemIndex = -1;
	var LastSelectedField;
 
	var CurrentSection = GraphWizard.CurrentSection;
	var SelectWindow = ShowSelectObjectByRelationWindow(CurrentSection.MainTableUSI, smField,
		tlmAllLinks, "Выбор поля фильтрации", null, null, true);
	if (!Assigned(SelectWindow)) {
		return;
	}
	var Results = SelectWindow.Attributes('Results');
	var Path, FBItemIndex, Column, FBItem, Result;
	for (var i = 0, Count = Results.length; i<Count; i++) {
		Result = Results[i];
		Path = Result.Column.FieldPath;
		FBItemIndex = -1;
		if (FiltersBuilderItem) {
			RemoveFilterItem(FiltersBuilderItem);
			FBItemIndex = FiltersBuilder.RootItems.GetIndexOfItem(FiltersBuilderItem);
			FiltersBuilder.RootItems.Remove(FiltersBuilderItem);
		}
		Column = AddFilterItem(Path, null);
		Column.Caption = Result.Column.Caption;
		var CustomDataset = CreateCustomDataset();
		GraphWizard.CustomDataset = CustomDataset
		FiltersBuilder.Dataset = System.EmptyValue;
		FiltersBuilder.Dataset = CustomDataset;
		var DataFields = CustomDataset.DataFields;
		var DataField = null;
		if ((Result.IsLookup != 0) && (Result.IsLookup != null)) {
			DataField = DataFields.ItemsByName(Column.ColumnAlias + 'ID')
		}
		if (!Assigned(DataField)) {
			DataField = DataFields.ItemsByName(Column.ColumnAlias);
		}
		FBItem = FiltersBuilder.RootItems.CreateItemByDataField(DataField);
		if (FBItemIndex < 0) {
			FiltersBuilder.RootItems.Add(FBItem);
		} else {
			FiltersBuilder.RootItems.InsertItem(FBItemIndex, FBItem);
		}
		FBItem.Enabled = true;
		FBItem.RefreshDisplayValue();
		FBItem.ValueNotSet = true;
		FilterBuilderControl.Refresh();
		AddFilterItem(Path, FBItem);
	}
	SetIsChanged();
}
 
function ShowSelectObjectByRelationWindow(MainTableUSI, Mode, TablesListMode,
	WindowCaption, LastSelectedField, ExceptDataTypes, IsHistoryVisible, LinksVisibility,
	OnlyLookupFieldsForTableUSI) {
	var SelectWindow = Services.GetNewItemByUSI('wnd_SelectObjectsByRelations');
	SetAttribute(SelectWindow, 'NotifyObject', Self);
	SetAttribute(SelectWindow, anMode, Mode);
	SetAttribute(SelectWindow, anMainTableUSI, MainTableUSI);
	SetAttribute(SelectWindow, anTablesListMode, TablesListMode);
	SetAttribute(SelectWindow, anDataTypes, ExceptDataTypes);
	if ((ExceptDataTypes) && (ExceptDataTypes.length > 0)) {
		SetAttribute(SelectWindow, anIsFieldDataTypeListIsExceptionList, true);
	}
	SetAttribute(SelectWindow, anLastSelected, LastSelectedField);
	SetAttribute(SelectWindow, anIsHighlightRelations, true);
	SetAttribute(SelectWindow, anOnlyLookupFieldsForTableUSI, 
		OnlyLookupFieldsForTableUSI);
	SetAttribute(SelectWindow, anWindowCaption, WindowCaption);
	SetAttribute(SelectWindow, 'HistoryPageName', "Поля графика");
 
	SetAttribute(SelectWindow, anIsColumnsHistoryVisible, IsHistoryVisible);
	if (!LinksVisibility) {
		SetAttribute(SelectWindow, anLinksVisibility, lvAll);
	} else {
		SetAttribute(SelectWindow, anLinksVisibility, LinksVisibility);
	}
	if (IsHistoryVisible) {
		var UserColumns = new Object();
		var Keys = new VBArray(GraphWizard.CurrentSection.Columns.Keys()).toArray();
		for (var i = 0; i < Keys.length; i++) {
			UserColumns[Keys[i]] = GetUserColumnByColumn(GraphWizard.
				CurrentSection.Columns(Keys[i]));
		}
		SetAttribute(SelectWindow, anColumnsHistory, UserColumns);
	}
 
	SelectWindow.Prepare();
	if (SelectWindow.ShowModal() != wmrOK) {
		return null;
	}
	return SelectWindow;
}

 

Зверев Александр,

Благодарю за помощь.

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

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

Нет, там только поля. Значение в карточке настройки графика вводится как в обычном фильтре раздела.

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

У меня в 3.3.2 у FiltersBuilderControl нет события OnFiltersBuilderValueSelect. Только OnFiltersBuilderItemSelect и OnFiltersBuilderItemRemove 

 

 

 

 

 

 

 

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

Интересно вот это окно доступно как сервис конфигурации?

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

Окно больше похожее на генерируемое ядром.

Зверев Александр пишет:

Можно пойти с другой стороны и модифицировать согласно потребностям стандартное окно выбора, если оно открылось из блока фильтрации.

Так и собирался сделать. Но мне нужен обработчик события, в котором я могу установить атрибуты для окна wnd_MultiSelectData. Но если примеров реализации толком нет, то не вижу смыла тратить время и просто добавлю LookupControl и в OnPrepareSelectWindow заполню все как мне нужно.

Еще раз благодарю за помощь.

Можно поступить, как во всех боле-менее нестандартных разделах (задачи, проекты): добавить в fmGroupsWindow выше wndGroups новый fg и туда добавить этот LookupControl. Он отобразится выше дерева групп. А логику дополнительной фильтрации привязать, как это сделано в указанных разделах.

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

Приветствую. Проблема с созданием Join'а.

Имеется вот такой SelectQuery.

SELECT
    [tbl_OfferingInMovement].[ID] AS [ID],
    [tbl_OfferingInMovement].[OfferingMovementID] AS [OfferingMovementID],
    [tbl_OfferingInMovement].[OfferingID] AS [OfferingID],
    [Offering].[Name] AS [OfferingName],
    [Offering].[Code] AS [OfferingCode],
    [Unit].[Name] AS [UnitName],
    [OfferingMovement].[StoreID] AS [StoreID],
    [tbl_Store].[Store] AS [Store],
    [tbl_OfferingInMovement].[Quantity] AS [Quantity],
    [tbl_OfferingInMovement].[BasicPrice] AS [BasicPrice],
    [tbl_OfferingInMovement].[BasicAmount] AS [BasicAmount],
    [tbl_OfferingInMovement].[SignedQuantity] AS [SignedQuantity],
    [tbl_OfferingInMovement].[SignedAmount] AS [SignedAmount],
    [tbl_OfferingInMovement].[Description] AS [Description],
    [OfferingMovementType].[ID] AS [OfferingMovementTypeID],
    [OfferingMovementType].[Name] AS [OfferingMovementType],
    [tbl_OfferingInMovement].[PlanQuantity] AS [PlanQuantity],
    [tbl_OfferingInMovement].[PlanAmount] AS [PlanAmount],
    [OfferingMovement].[StatusID] AS [OfferingMovementStatusID],
    [tbl_OfferingInMovement].[Price] AS [Price],
    [tbl_OfferingInMovement].[Amount] AS [Amount],
    [OfferingMovement].[CurrencyID] AS [CurrencyID],
    [tbl_Currency].[Currency] AS [Currency],
    [OfferingMovement].[CurrencyRate] AS [Rate],
    [tbl_OfferingInMovement].[ConsignmentID] AS [ConsignmentID],
    [Consignment].[Number] AS [ConsignmentNumber],
    [Offering].[OfferingChargeMethodID] AS [OfferingChargeMethodID],
    [OfferingMovement].[Number] AS [OfferingMovementNumber],
    [tbl_OfferingInMovement].[TZR] AS [TZR],
    [tbl_OfferingInMovement].[PrimeCost] AS [PrimeCost],
    [tbl_OfferingInMovement].[PrimeAmount] AS [PrimeAmount],
    [Offering].[Volume] AS [Volume],
    [Offering].[Weight] AS [Weight],
    [Offering].[BasicPrice] AS [OfferingBasicPrice],
    [tbl_OfferingInMovement].[TZRAmount] AS [TZRAmount],
    [tbl_OfferingInMovement].[DocumentID] AS [DocumentID],
    [tbl_OfferingInMovement].[ContractID] AS [ContractID],
    [tbl_OfferingInMovement].[InvoiceID] AS [InvoiceID],
    [tbl_Document].[Title] AS [DocumentNumber],
    [tbl_Contract].[Title] AS [ContractNumber],
    [tbl_Invoice].[InvoiceNumber] AS [InvoiceNumber],
    [tbl_OfferingInMovement].[PurchaseID] AS [PurchaseID],
    [tbl_Purchases].[Number] AS [PurchaseNumber],
    [OfferingMovement].[SupplierID] AS [SupplierID],
    [tbl_OfferingInMovement].[Date] AS [Date],
    [OfferingMovement].[ModifiedOn] AS [ModifiedOn],
    [OfferingMovement].[DateOfShipment] AS [DateOfShipment],
    [AccountBillingInfoItelon].[Name] AS [ItelonName],
    [AccountBillingPayerInfo].[Name] AS [PayerName]
FROM
    [dbo].[tbl_OfferingInMovement] AS [tbl_OfferingInMovement]
LEFT OUTER JOIN
    [dbo].[vw_Offering] AS [Offering] ON [Offering].[ID] = [tbl_OfferingInMovement].[OfferingID]
LEFT OUTER JOIN
    [dbo].[tbl_Unit] AS [Unit] ON [Unit].[ID] = [Offering].[DefaultUnitID]
LEFT OUTER JOIN
    [dbo].[vw_OfferingMovement] AS [OfferingMovement] ON [OfferingMovement].[ID] = [tbl_OfferingInMovement].[OfferingMovementID]
LEFT OUTER JOIN
    [dbo].[tbl_OfferingMovementType] AS [OfferingMovementType] ON [OfferingMovementType].[ID] = [OfferingMovement].[TypeID]
LEFT OUTER JOIN
    [dbo].[tbl_Store] AS [tbl_Store] ON [tbl_Store].[ID] = [OfferingMovement].[StoreID]
LEFT OUTER JOIN
    [dbo].[vw_OfferingMovement] AS [Consignment] ON [Consignment].[ID] = [tbl_OfferingInMovement].[ConsignmentID]
LEFT OUTER JOIN
    [dbo].[tbl_Currency] AS [tbl_Currency] ON [tbl_Currency].[ID] = [OfferingMovement].[CurrencyID]
LEFT OUTER JOIN
    [dbo].[vw_Document] AS [tbl_Document] ON [tbl_Document].[ID] = [tbl_OfferingInMovement].[DocumentID]
LEFT OUTER JOIN
    [dbo].[vw_Contract] AS [tbl_Contract] ON [tbl_Contract].[ID] = [tbl_OfferingInMovement].[ContractID]
LEFT OUTER JOIN
    [dbo].[vw_Invoice] AS [tbl_Invoice] ON [tbl_Invoice].[ID] = [tbl_OfferingInMovement].[InvoiceID]
LEFT OUTER JOIN
    [dbo].[vw_Purchases] AS [tbl_Purchases] ON [tbl_Purchases].[ID] = [tbl_OfferingInMovement].[PurchaseID]
LEFT OUTER JOIN
    [dbo].[tbl_AccountBillingInfo] AS [AccountBillingInfoItelon] ON [AccountBillingInfoItelon].[ID] = [OfferingMovement].[InfoItelonID]
LEFT OUTER JOIN
    [dbo].[tbl_AccountBillingInfo] AS [tbl_AccountBillingInfoPayer] ON [tbl_AccountBillingInfoPayer].[ID] = [tbl_OfferingInMovement].[PayerID]

Предпоследний Join(AS [AccountBillingInfoItelon]) создан мною. Работает отлично.

Вот его код. Заранее извиняюсь за синтаксис VBA.

    Set oTable = TSConnector.Services.GetNewItemByUSI(AccountBillingInfoTableName)
    Set oJoin = oSelectQuery.Items(0).Joins.Items(4).CreateCopy
    oJoin.UID = TSConnector.GenGUID
    oJoin.RightField = oJoin.RightField.ParentFields.Items(40)
    oJoin.LeftField = oTable.Fields.ItemsByName("ID")
    oJoin.LeftTableAlias = "AccountBillingInfoItelon"
    oJoin.JoinType = jtLeftOuter
    oSelectQuery.Items(0).Joins.AddItem oJoin
    oSelectQuery.Items(0).Joins.Items(oSelectQuery.Items(0).Joins.Count - 1).CanDisable = False

Последний создаётся не правильно.

    Set oJoin = oInvoiceSelectQuery.Items(0).Joins.Items(0).CreateCopy
    oJoin.UID = TSConnector.GenGUID
    oJoin.LeftField = oTable.Fields.ItemsByName("ID")
    oJoin.LeftTableAlias = "tbl_AccountBillingPayerInfo"
    oJoin.RightField = TSConnector.Services.GetNewItemByUSI(InvoiceTableName).Fields.Items(31)
    oJoin.JoinType = jtLeftOuter
    oSelectQuery.Items(0).Joins.AddItem oJoin
    oSelectQuery.Items(0).Joins.Items(oSelectQuery.Items(0).Joins.Count - 1).CanDisable = False

Проблема с RightField. Поле верное, то что нужно [PayerID]. Но мне надо чтобы оно доставала его именно из [tbl_Invoice]. А она же в SQL подставляет [tbl_OfferingInMoment]. Где можно изменить таблицу в Join'е или ещё где-то в SelectQuery. Целую неделю мучаюсь не могу понять.

Нравится

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

В коробке в скрипте wnd_IWTGraphWizardScript есть функция:

function GetPathByColumn(Column) {
	var Result = Column.Field.ParentFields.ParentTable.UID + snpFields + Column.Field.UID;
	var ParentJoin = Column.ParentJoin;
	while (ParentJoin) {
		Result = ParentJoin.RightField.ParentFields.ParentTable.UID +
			snpFields +
			ParentJoin.RightField.UID +
			jtLeft +
			ParentJoin.LeftField.ParentFields.ParentTable.UID +
			snpFields +
			ParentJoin.LeftField.UID +
			snpSegment +
			Result;
		ParentJoin = ParentJoin.ParentJoin;
	}
	return Result;
}  

Возможно, подобным образом можно не только считывать, но и записывать название таблицы. Если разобраться не получится, можно попробовать подключится в отладчике и посмотреть, как устроены нормально работающие join-ы.

 

О, спасибо Александр! Не думал что достучусь на этот форум. laugh Завтра с утра буду пробовать. Спасибо ещё раз. Отпишу что да как. 

Не получилось записывать название таблицы в Join. Что за связь используется так и не получилось выяснить. Я пользуюсь редактором VBA непосредственно в EXCEL. За Visual Studio еще не садился.

Воспользовался oSubSelectColumn. Отличная штука. Всё что хотел, получилось.

    Set oSubSelectColumn = oSelectQuery.Items(0).Columns.CreateSubSelectColumn
    Set oTable = TSConnector.Services.GetNewItemByUSI(AccountBillingInfoTableName)
 
    Dim oSQLFilter As CustomSQLFilter
    Dim oSelect As TSObjectLibrary.Select
    Set oSelect = oSelectQuery.CreateItem
    oSelect.FromTable = oTable
    oSelect.FromTableAlias = "AccountBillingInfo"
    Set oGeneralColumn = oSelectQuery.Columns.CreateGeneralColumn
    oGeneralColumn.Field = oTable.Fields.ItemsByName("Name")
    oGeneralColumn.ColumnAlias = "Name"
    oSelect.Columns.Add oGeneralColumn
    Set oSQLFilter = oSelect.Filters.CreateCustomSQLFilter
    oSQLFilter.SQLText = "[AccountBillingInfo].[ID] = [OfferingMovement].[InfoItelonID]"
    oSelect.Filters.Add oSQLFilter
    oSubSelectColumn.ColumnSelectQuery.Add oSelect
    oSubSelectColumn.ColumnAlias = "AccountBillingInfoItelon"
    oSelectQuery.Items(0).Columns.Add oSubSelectColumn
    oSelectQuery.Items(0).Columns.Items(oSelectQuery.Items(0).Columns.Count - 1).IsEnabled = True

 

В редакторе VBA тоже есть отладка. Не знаю, показывает ли структуру объектов, но вроде бы должен.

Можно и через SubSelect. Когда-то в базе на Orcacle упирались в лимит Join-ов и приходилось в дизайнере переделывать в sq часть колонок на колонки-подзапросы.

Зверев Александр, есть, да, структура объектов.

Если видно структуру, можно посмотреть, как устроен нормальный join. Ну, или использовать подзапросы.

Зверев Александр, Пользовался более года подзапросами. Сегодня столкнулся с проблемой фильтрации по столбцам от подзапросов. Долго не стал вникать в суть проблемы.

Решил вернуться к Join'ам. smiley

Решение к проблеме в самом низу этого сообщения.

Пошёл по вашему совету, Александр. Решил сравнивать структуры созданного мною нового Join'а и уже готового Join'а из другого готового SelectQuery.

Задача была поставлена аналогична упомянутой выше: прикрепить таблицу(создать join) к запросу(SelectQuery). При этом из прикрепленной таблицы(join'а) должны выбираться те строки, значения ключевых полей которых равны значениям полей не из исходной таблицы, на основе которой сформирован запрос(SelectQuery), а из таблицы, прикрепленной ранее (уже прикрепленного join'а). Всё тоже самое, что и в предыдущей задаче. Выражаясь кратким языком, присоединить join к уже имеющемся join'у в SelectQuery.

На следующей картинке представлен SQL текст уже (упомянутого в первом сообщения топика) готового запроса "sq_OfferingInMovement", сформированный на основе таблицы "tbl_OfferingInMovement" и нескольких прикрепленных таблиц к нему. В этом тексте можно увидеть, что к запросу прикреплена таблица(join), к заранее прикрепленному (join'у). В этом запросе всё правильно.

Синим выделены строки, означающие что к запросу прикреплено представление(если не понятно что такое представление, можно прочесть как "таблица") "[vw_Offering], у которого значение ключевого поля "[ID]" равняется значению поля исходной таблицы  "[tbl_OfferingInMovement].[OfferingID]". Этому присоединенному представлению присвоен псевдоним(alias) "[Offering]".

Красным выделены строки, означающие что к запросу прикреплена таблица "[tbl_Unit]", у которого значение ключевого поля "[ID]" равняется значению поля не исходной таблицы, а значению поля прикрепленного (синим выделено) представления [Offering].[DefaultUnitID].

В этом примере всё отлично.

Проблема заключалась в том, что при создании нового собственного прикрепления (join'а), которое должно было крепиться к уже имеющемуся прикреплению (join'у), в SQL тексте отображалось что новое прикрепление (join) крепиться не к уже имеющемуся прикреплению, а к исходной таблице. То есть, если взять пример выше, и прикрепление, которое выделено красным, было бы создано мною, то там вместо [Offering].[DefaultUnitID] было бы [tbl_OfferingInMovement][DefaultUnitID], что было бы неверным и, естественно, выдавало бы ошибку. Так как в [tbl_OfferingInMovement] нет поля [DefaultUnitID] и вообще это не то что мне нужно.

В ходе сравнения join'ов выяснилось, что у объекта Join, оказывается, есть параметр ParentJoin, которому необходимо присваивать тот Join, к которому будет необходимо прикреплять новый join.

Вот код правильно созданного Join'а и необходимого нам столбца из него.

Создание нового прикрепления (join'а) к исходной таблице запроса.

 
//Таблица, строки которой будем крепить. 
   Set objTSTable = objTSConnector.GetService(strAssemblingInTaskTableName)
 
   Set objTSAssemblingInTaskJoin = objTSSelect.Joins.CreateItem
   objTSAssemblingInTaskJoin.ParentJoins = objTSSelect.Joins
   objTSAssemblingInTaskJoin.LeftField = objTSTable.Fields.ItemsByName("ID")
   objTSAssemblingInTaskJoin.RightField = 
   objTSSelect.FromTable.Fields.ItemsByName("AssemblingInTaskID")
   objTSSelect.Joins.Add objTSAssemblingInTaskJoin

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

    Set objTSColumn = objTSSelect.Columns.CreateGeneralColumn
    objTSColumn.ParentColumns = objTSSelect.Columns
    objTSColumn.ParentJoin = objTSAssemblingInTaskJoin
    objTSColumn.ParentParametriticQuery = objTSSelectQuery
    objTSColumn.Field = objTSTable.Fields.ItemsByName("TaskID")
    objTSColumn.DependsOn.CommaText = objTSTable.SQLName
    objTSSelect.Columns.Add objTSColumn
    objTSColumn.IsEnabled = True

Теперь добавляем ещё одно прикрепление (join) к уже созданному выше прикреплению.

    'Таблица нового прикрепления.
    Set objTSTable = objTSConnector.GetService(strTaskTableName)
 
    Set objTSTaskJoin = objTSSelect.Joins.CreateItem
 
    'Вот здесь обязательно указать то прикрепление, к которому будем крепить это.
    objTSTaskJoin.ParentJoin = objTSAssemblingInTaskJoin
 
    objTSTaskJoin.ParentJoins = objTSSelect.Joins
    objTSTaskJoin.LeftField = objTSTable.Fields.ItemsByName("ID")
    objTSTaskJoin.RightField = objTSAssemblingInTaskJoin.LeftField.ParentFields.ItemsByName("TaskID")
    objTSSelect.Joins.Add objTSTaskJoin

Ну и добавляем обязательно столбец из этого прикрепления. Без него join не включиться, если не указать параметр у Join'а CanDisable = False. Без особой причины CanDisable можно не трогать. Достаточно просто добавить столбец из этого join'а, как его параметр IsEnabled сразу же станет True.

    Set objTSColumn = objTSSelect.Columns.CreateGeneralColumn
    objTSColumn.ParentColumns = objTSSelect.Columns
    objTSColumn.ParentJoin = objTSTaskJoin
    objTSColumn.ParentParametriticQuery = objTSSelectQuery
    objTSColumn.Field = objTSTable.Fields.ItemsByName("StatusID")
    objTSColumn.DependsOn.CommaText = objTSTable.SQLName
    objTSSelect.Columns.Add objTSColumn
    objTSColumn.IsEnabled = True

Всё.

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

Если есть какие-то замечания, то обязательно напишите.

Можно и так. Всё ли правильно, по коду сказать сложно. Если в результате в профайлере идёт нужный SQL-запрос, то нормально.

По поводу свойства ParentJoin, в SDK о нём есть, но очень кратко. Лучше смотреть примеры использования поиском по скриптам конфигурации.

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

При открытии любого дата контрола выпадает критическая ошибка: "Invalid Argument to date encode"

Ошибка воспроизводится только при выборе декабря 2017 года. Остальные даты не ругаются.

TSXRM 

Версия 3.3.2.43

На версии 3.3.2.309 - ошибка не воспроизводится.

Подскажите пожалуйста можно ли это исправить?

 

Нравится

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

В каждом вопросе кроется половина ответа. Исправить можно путём обновления файлов до 3.3.2.309.

а у вас календарь не заканчивается 2017 годом?

Стандартно календарь оканчивается в 2015. Как продлить, писал тут.

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

Хочу DataSet, создаваемый SelectQuery, вывести в Excel через VBA. С этим проблем нет. SelectQuery является готовым сервисом, созданным администратором. К админке доступа нету. Всё прекрасно работает. Проблема в одном. Не могу Join по нормальному прикрепить.

Вот SQLText это SelectQuery:

SELECT
    [Offering].[Name] AS [OfferingName],
    [Offering].[Code] AS [OfferingCode],
    [tbl_OfferingInMovement].[Quantity] AS [Quantity],
    [OfferingMovementType].[Name] AS [OfferingMovementType],
    [OfferingMovement].[StatusID] AS [OfferingMovementStatusID],
    [tbl_OfferingInMovement].[InvoiceID] AS [InvoiceID],
    [tbl_Invoice].[InvoiceNumber] AS [InvoiceNumber],
    [tbl_OfferingInMovement].[Date] AS [Date]
FROM
    [dbo].[tbl_OfferingInMovement] AS [tbl_OfferingInMovement]
LEFT OUTER JOIN
    [dbo].[vw_Offering] AS [Offering] ON [Offering].[ID] = [tbl_OfferingInMovement].[OfferingID]
LEFT OUTER JOIN
    [dbo].[vw_OfferingMovement] AS [OfferingMovement] ON [OfferingMovement].[ID] = [tbl_OfferingInMovement].[OfferingMovementID]
LEFT OUTER JOIN
    [dbo].[tbl_OfferingMovementType] AS [OfferingMovementType] ON [OfferingMovementType].[ID] = [OfferingMovement].[TypeID]
LEFT OUTER JOIN
    [dbo].[vw_Invoice] AS [tbl_Invoice] ON [tbl_Invoice].[ID] = [tbl_OfferingInMovement].[InvoiceID]
LEFT OUTER JOIN
    [dbo].[tbl_AccountBillingInfo] AS [AccountBillingInfoItelon] ON [AccountBillingInfoItelon].[ID] = [OfferingMovement].[InfoItelonID]

Последняя строка, добавленный мной JOIN. Он работает на отличненько.

Его код(кстати, скажите насколько он крив):

    Set oTable = TSConnector.Services.GetNewItemByUSI(AccountBillingInfoItelonTableName)
    Set oJoin = oSelectQuery.Items(0).Joins.Items(4).CreateCopy ' создание копии join'а LEFT OUTER JOIN [dbo].[tbl_OfferingMovementType] AS [OfferingMovementType] ON [OfferingMovementType].[ID] = [OfferingMovement].[TypeID]
    oJoin.UID = TSConnector.GenGUID
    oJoin.RightField = oJoin.RightField.ParentFields.Items(40) 'нужное поле из OfferingMovement
    oJoin.LeftField = oTable.Fields.ItemsByName("ID")
    oJoin.LeftTableAlias = "AccountBillingInfoItelon"
    oJoin.JoinType = jtLeftOuter
    oSelectQuery.Items(0).Joins.AddItem oJoin
    oSelectQuery.Items(0).Joins.Items(oSelectQuery.Items(0).Joins.Count - 1).CanDisable = False

А вот этот не хочет:

    Set oTable = TSConnector.Services.GetNewItemByUSI(InvoiceTableName)
    Set oJoin = oSelectQuery.Items(0).Joins.Items(10).CreateCopy
    oJoin.UID = TSConnector.GenGUID
    oJoin.RightField = oSelectQuery.Items(0).Joins.Items(9).LeftField.ParentFields.ItemsByName("PayerID") 'проблема именно здесь. Крепиться Field от tbl_Invoice. Но в SQL_Text ошибка. Крепит Field от не того Table.
    oJoin.LeftField = oTable.Fields.ItemsByName("ID")
    oJoin.LeftTableAlias = "AccountBillingPayerInfo"
    oJoin.JoinType = jtLeftOuter
    oSelectQuery.Items(0).Joins.AddItem oJoin
    oSelectQuery.Items(0).Joins.Items(oSelectQuery.Items(0).Joins.Count - 1).CanDisable = False

После него в SQLText в конце появляется:

LEFT OUTER JOIN
    [dbo].[vw_Invoice] AS [AccountBillingPayerInfo] ON [AccountBillingPayerInfo].[ID] = [tbl_OfferingInMovement].[PayerID]

В результате ошибка. В конце должно быть не [tbl_OfferingInMovement].[PayerID], а [tbl_Invoice].[PayerID]. Ведь креплю то я PayerID именно от tbl_Invoice. А в SQLText он зачем-то подставляет PayerID из tbl_OfferingInMovement, которого там нету. Именно в этом ошибка. Где вообще в SelectQuery эти прикрепленные таблицы?

Я может быть как-то не правильно Field добавляю в Join'ы. И до конца не понимаю суть этих Field'ов. 

Может быть как-то с нуля можно создать этот join. Есть ли какие нибудь статьи?

 

Нравится

1 комментарий
Вопрос

В скрипте scr_BaseDBEditUtils есть функция:

function OpenDatasetWithRecordID(Dataset, ID) {

    Dataset.Close();

    ApplyDatasetIDFilter(Dataset, ID, true);

    Dataset.Open();

}

на одной из деталей вместо фильтра по ID в запросе появляется "where (1 = 0)" (смотрел в профайлере), естественно запрос ничего не возвращает и пользователь получает сообщение о том, что у него нет прав на эту запись.

Что это и как устранить?

Прикрепленные файлы

Нравится

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

Без конкретики сказать сложно. Может, в самом SelectQuery этой детали есть такой фильтр и он включается при включении фильтра с кодом «ID».

Какая именно конкретика может помочь? Могу сам сервис показать. Прикрепил к первому сообщению.

Тут было такое же 1=0 и дело было в отсутствии прав на таблицу.

Присмотрелся, оказывается в запросе еще и таблицы подменяются на просмотры - tbl_SWTwo на vw_SwTwo и tbl_Contact на vw_Contact. Это что значит?

При этом под администратором никаких подмен не происходит.

 

Если это как-то связано с правами, то как их правильно раздать? Получается пользователь добавить запись может, а редактировать нет.

То, что таблицы подменяются на view, это нормально. Так реализовано ограничение прав на записи для неадминистраторов.

По изначальному вопросу, правильно раздать так, чтобы были права на этот объект. См. раздел прав доступа на группы таблиц.

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

Если бы права были, не было бы 1=0. Возможно, права не на основную таблицу запроса, а другую, в нём упомянутую. Можно записать профайлером один и тот же запрос под администратором и пользователем, а затем сравнить, что именно в нём заменилось.

Я так и сделал. Дал права на всё, что там используется, таблицы на просмотры у пользователя теперь не заменяются, а where (1 = 0) так и осталось.

Значит, нужно искать, что заменено на 1=0 и дать права на него.

На 1=0 заменен фильтр ID = '{GUID}'. На что давать права?

Права на нужные таблицы и/или поля. Вы можете подключиться в Management Studio под этим пользователем и сами увидеть, что ему доступно, а что нет. Можете запустить запрос, записанный в профайлере и увидеть, чего не хватает.

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

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