Вопрос

Добрый день!
Есть бизнес-процесс, который стартует в разделе "Проекты" по кнопке "Запустить процесс" следующим образом:

var Dataset = dlData.Dataset;
var ParamNames = new Array();
ParamNames[0] = 'OpportunityID';
var ParamValues = new Array();
ParamValues[0] = Dataset.Values('ID');
WFStartByID("{96A6BC55-B2F9-499C-A2E0-66FD2DF13B32}", ParamNames, ParamValues);

Запускается задача ( 1 шаг бизнес-процесса). Необходимо, чтобы в эту задачу ( только в эту) в качестве даты начала и даты завершения брались значения из специальных полей в проекте.
Подскажите, пожалуйста как можно это сделать ( пробовали передавать эти значения аналогично ParamNames[0] = 'OpportunityID' - не получилось)
Версия Террасофта 3.0.4.118 Х25

У меня такой же вопрос

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

Дарья, попробуйте передавать эти значения в параметры, как и OpportunityID (например, с названиями StartDate и DueDate), а при обработке события OnExecute элемента wa_TaskAction проверять название элемента и в зависимости от него устанавливать даты начала и завершения задач:

function wa_TaskActionOnExecute(WorkflowAction, ActionItem, ItemDataset,
		IsComplete, ResultLinkCodes) {
	.........
	var DefaultValues = GetNewDictionary();
	DefaultValues.Add('Title', ActionItem.Caption);
	DefaultValues.Add('WorkflowItemID', ItemID);
	if (ActionItem.Name == '<Название задачи - первого элемента БП>') {
		var Diagram = GetDiagramByItem(ActionItem);
		var ExecuteDate = WFGetParamValue(Diagram, 'StartDate');
		var DueDate = WFGetParamValue(Diagram, 'DueDate');
		DefaultValues.Add('StartDate', ExecuteDate);
		DefaultValues.Add('DueDate', DueDate);
	} else {
		var ExecuteDate = ItemDataset.ValAsDateTime('ExecuteDate');
		var ExecuteAfterTimeTypeID = 
			WFGetParamsMapItemValue(ActionItem, 'ExecuteAfterTimeTypeID');
		var ExecuteAfterTimeValue = 
			parseInt(WFGetParamsMapItemValue(ActionItem, 'ExecuteAfterTimeValue'));
		ExecuteDate = WFCalcExecuteTime(ExecuteDate, ExecuteAfterTimeTypeID, 
			ExecuteAfterTimeValue);
		ExecuteDate = ExecuteDate.getVarDate();
		DefaultValues.Add('StartDate', ExecuteDate);
		var ExecuteTimeTypeID = 
			WFGetParamsMapItemValue(ActionItem, 'ExecuteTimeTypeID');
		var ExecuteTimeValue = 
			parseInt(WFGetParamsMapItemValue(ActionItem, 'ExecuteTimeValue'));
		var DueDate = WFCalcExecuteTime(ExecuteDate, ExecuteTimeTypeID, 
			ExecuteTimeValue);
		DefaultValues.Add('DueDate', DueDate.getVarDate());
	}
	..........
}

Спасибо.
Скажите, пожалуйста, надо ли подключать дополнительные скрипты?
Сейчас возникает ошибка
на строчке var Diagram = GetDiagramByItem(ActionItem);
"Предполагается наличие объекта"

Должен быть подключен скрипт scr_WorkflowUtils.

Возможно, в версии 3.0.4 ещё не было этой функции. В этом случае Вы можете её добавить самостоятельно в скрипт scr_WorkflowUtils. Её текст такой:

function GetDiagramByItem(DiagramItem) {
	return DiagramItem.ParentItems.ParentDiagram;
}

Либо вместо вызова var Diagram = GetDiagramByItem(ActionItem); вставьте такую строчку:

var Diagram = ActionItem.ParentItems.ParentDiagram;
Войдите или зарегистрируйтесь, чтобы комментировать
Вопрос

Добрый день.

Я создала новое поле в сервисе sq_Task 'Колонка с типом SQL'. Там написала запрос:

case when isnull((SELECT acc.MyColumn FROM tbl_Account acc
 WHERE tbl_Task.AccountID = acc.ID), '') = '' then ''
else
isnull((SELECT StringValue FROM tbl_SystemSetting WHERE Code = 'MyCode'), '')
 + isnull((SELECT cast(acc.MyColumn AS nvarchar(max)) FROM tbl_Account acc
 WHERE tbl_Task.AccountID = acc.ID ), '')
 end

в датасете добавила поле типа справочник и указала там эту колонку, оставив поле "источник" пустым.
Теперь при открытии карточки задачи пользователем бз админских прав у меня вылетает ошибка
"The Select permission was denied on the object 'tbl_Account', database 'CRM', achema 'dbo'"

Что-то с правами не так?

У меня такой же вопрос

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

Kat, да проблема с правами. Если говорить, не вдаваясь сильно глубоко, то Вы должны заменять названия таблиц tbl_Account, tbl_Task на vw_Account, vw_Task если конфигурация работает под пользователем, а не администратором.

Александр, спасибо!
поменяла в своем запросе tbl_Account на vw_Account

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

Все работает и под админом корректно сейчас.
На будущее: нужно прямо текст запроса менять перед открытием? Или есть способы попроще?

"Kat" написал:Все работает и под админом корректно сейчас.

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

"Kat" написал:На будущее: нужно прямо текст запроса менять перед открытием? Или есть способы попроще?

По как что способа проще нет. Да и куда уж проще:)

Есть другая проблема. При открытии карточки (только при создании записи не админом), которая на датасет ссылается, где я запрос написала, вылетает ошибка
"Ошибка выполнения метода 'wnd_MyWindowEditOnPrepare'. OLE error 80020102"
Когда отключаю поле с запросом в сервисе, тогда ошибки нет.

Kat, Вы не проверяли с помощью профайлера, какой запрос посылается на сервер при открытии карточки пользователем? Проверьте, пожалуйста, и попробуйте выполнить этот запрос в SQL Management Studio (или Query Analyzer).

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

Так сообщение возникает при открытии карточки, или при попытке сохранения? Отладчик запускается, или просто возникает окно лога?

Отладчик появляется и потом лог. Это при попытке открыть карточку новой задачи.

Можете сказать, в каком скрипте и каком месте останавливается отладчик?

Да.вот:

function ProcessBaseDBEditOnPrepare(Window, BaseDBEdit){
	try {
		var Datalink = Window.ComponentsByName('dlData');
		InitializeDBEdit(Datalink, BaseDBEdit, Window);
		if (BaseDBEdit.RecordID == GUID_NULL) {
		    if (BaseDBEdit.IsCopy){
		        CopyRecord(BaseDBEdit, Window);
			} else {
			    AppendRecord(BaseDBEdit, Window);
			}
		} else {
			if (!EditRecord(BaseDBEdit, Window)) {
				return;
			}
		}
		var btnOK = Window.ComponentsByName('btnOK');
		EnableOKButtonByRights(btnOK, BaseDBEdit);
	} finally {/// дебагер кидает сюда
		Window.Attributes('WindowWasPrepared') = true;
	}
}

Если в отладчике переместиться выше, то можно отследить следующее. Мы попадаем в:

function EditRecord(BaseDBEdit, Window) {
	var Dataset = BaseDBEdit.Dataset;
	OpenDatasetWithRecordID(Dataset, BaseDBEdit.RecordID);
	if (IsDatasetEmpty(Dataset)) {
	    var Message = "Запись удалена";
	    if (!Connector.CurrentUser.IsAdmin) {
	        Message += ' ' + "или" + ' ' +
				"текущий пользователь не имеет достаточно прав для чтения записи";
		}
		ShowWarningDialog(Message);
		var btnOK = Window.ComponentsByName('btnOK');
		EnableControl(btnOK, false);
		return false;//проваливаемся до сюда
	}	
	Dataset.Edit();
	SetEditWindowCaption(BaseDBEdit, Window);
	return true;
}

Попадаем сюда, потому что BaseDBEdit.RecordID не нулевой, хотя задачу только создаем.

Kat, попробуйте добавить строчку debugger; сразу после try {. Потом перезапустите Terrasoft и добавьте новую запись. После того, как отладчик остановится на строке c debugger, пройдитесь дальше в ручном режиме и определите, где на самом деле происходит сбой.

Проваливаюсь в:

function AppendRecord(BaseDBEdit, Window) {
	var Dataset = BaseDBEdit.Dataset;
	var Attributes = Window.Attributes;
	var DoDisableEvents = !Attributes('DoNotDisableEvents');
	BaseDBEdit.RecordID = Connector.GenGUID();
	Dataset.DisableGettingDisplayValues();
	try {
	Dataset.Append();
	if (DoDisableEvents) {
		Dataset.DisableEvents();
	}
	try {
		Dataset.ValAsGUID('ID') = BaseDBEdit.RecordID;
		Window.Attributes('RecordID') = BaseDBEdit.RecordID;
		if ((!IsEmptyValue(BaseDBEdit.ParentItemID)) &&
			(!IsEmptyValue(BaseDBEdit.ParentItemFieldName))) {
			var DataField = Dataset.DataFields(BaseDBEdit.ParentItemFieldName);
			if (Assigned(DataField)) {
				DataField.Value = BaseDBEdit.ParentItemID;
			}
		}
		SetDefaultValues(BaseDBEdit);
	} finally {
		if (DoDisableEvents) {
			Dataset.EnableEvents();
		}
	}
	} finally {
		Dataset.EnableGettingDisplayValues();//падает здесь
	}
	SetEditWindowCaption(BaseDBEdit, Window);
}

Думаю, дело в

"Kat" написал:в датасете добавила поле типа справочник и указала там эту колонку, оставив поле "источник" пустым.

Ядро пытается определить колонку для отображения для этого поля, но у него ничего не получается, так как датасет не указан.

Попробуйте удалить из датасета поле типа "Справочник" и добавить обычное текстовое поле.

гениально) спасибо огромное за потраченное время!!!

Добрый день у меня та же ошибка. В SelectQuery есть колонка подзапроса, в которой есть колонка с текстом SQL (если ее отключить все работает). Ошибка вылетает только при открытии существующих записей и только если пользователь не администратор. Принажатии на кнопку "добавить" все работает.Вот скриншот. Как это можно обойти.

Михаил, думаю, Вы можете (поскольку всё-равно используете CustomSQL-колонку) внести все фильтры и используемые таблицы внутрь SQL-текста, не используя подзапрос (то есть, использовать CustomSQL-колонку непосредственно в основном запросе). А дальше - как уже было описано ранее: либо

"Kat" написал:поменяла в своем запросе

все tbl_ на vw_, либо

"Осауленко Александр" написал:Вам необходимо добавить логику перед открытием DataSet - заменять или нет таблицы на вью в БД

Лучше, конечно, второй вариант.

Спасибо за совет. Так и сделаю!

Я сделал, как Вы говорили, но под не-админом все равно эта колонка не работает (та же ошибка). На событии BeforeOpen заменяю значение свойства колонки SQLText из

(SELECT	SUM([Invoice].[Amount]) - SUM([Invoice].[PaymentAmount]) AS [DebtorAmount]
	FROM
		[dbo].[tbl_IssueInApplication] AS [IssueInApplication]
	LEFT OUTER JOIN
		[dbo].[tbl_Issue] AS [Issue] ON [Issue].[ID] = [IssueInApplication].[IssueID]
	LEFT OUTER JOIN
		[dbo].[tbl_OfferingInApplication] AS [OfferingInApplication] ON [OfferingInApplication].[ID] = [IssueInApplication].[OfferingInApplicationID]
	LEFT OUTER JOIN
		[dbo].[tbl_Application] AS [Application] ON [Application].[ID] = [OfferingInApplication].[ApplicationID]
	LEFT OUTER JOIN
		[dbo].[tbl_Invoice] AS [Invoice] ON [Invoice].[ApplicationID] = [Application].[ID]
	WHERE([IssueInApplication].[IsPlaced] = :IsPlaced AND
		[Application].[CustomerID] = [tbl_Account].[ID] AND
		[Issue].[StatusID] = :IssueIsClosed AND
		([Invoice].[BillStatusID] = :InvoiceWaiting OR
		[Invoice].[BillStatusID] = :InvoicePartPayed)))

на

(SELECT	SUM([Invoice].[Amount]) - SUM([Invoice].[PaymentAmount]) AS [DebtorAmount]
	FROM
		[dbo].[tbl_IssueInApplication] AS [IssueInApplication]
	LEFT OUTER JOIN
		[dbo].[vw_Issue] AS [Issue] ON [Issue].[ID] = [IssueInApplication].[IssueID]
	LEFT OUTER JOIN
		[dbo].[tbl_OfferingInApplication] AS [OfferingInApplication] ON [OfferingInApplication].[ID] = [IssueInApplication].[OfferingInApplicationID]
	LEFT OUTER JOIN
		[dbo].[vw_Application] AS [Application] ON [Application].[ID] = [OfferingInApplication].[ApplicationID]
	LEFT OUTER JOIN
		[dbo].[vw_Invoice] AS [Invoice] ON [Invoice].[ApplicationID] = [Application].[ID]
	WHERE([IssueInApplication].[IsPlaced] = :IsPlaced AND
		[Application].[CustomerID] = [tbl_Account].[ID] AND
		[Issue].[StatusID] = :IssueIsClosed AND
		([Invoice].[BillStatusID] = :InvoiceWaiting OR
		[Invoice].[BillStatusID] = :InvoicePartPayed)))

в строке

[Application].[CustomerID] = [tbl_Account].[ID] AND

[tbl_Account].[ID] берется из основного селекта.

Также есть еще одна проблема(номер ошибки тот же): не возможно удалить контрагента, если он указан в каком-то контакте. Воспроизводится даже под админом и даже если я эту колонку удаляю или пишу в ней просто 1

Михаил, у Вас в запросе используются как минимум две таблицы (tbl_IssueInApplication и tbl_OfferingInApplication). Они администрируются по записям? Вы смотрели профайлером, какой запрос посылается на сервер при открытии датасета? Предоставьте, пожалуйста, текст запроса и полный текст сообщения об ошибке.

По первой ошибке (открытие карточки редактирования контрагента не админом):
Текст запроса с профайлера:

exec sp_executesql N'SELECT
	[tbl_Account].[ID] AS [ID],
	[tbl_Account].[Name] AS [Name],
	[tbl_Account].[OfficialAccountName] AS [OfficialAccountName],
	[tbl_Account].[AnnualRevenue] AS [AnnualRevenue],
	[tbl_Account].[EmployeesNumber] AS [EmployeesNumber],
	[tbl_Account].[Address] AS [Address],
	[tbl_Account].[AddressTypeID] AS [AddressTypeID],
	[tbl_Account].[Communication1] AS [Communication1],
	[tbl_Account].[Communication1TypeID] AS [Communication1TypeID],
	[tbl_Account].[Communication2] AS [Communication2],
	[tbl_Account].[Communication2TypeID] AS [Communication2TypeID],
	[tbl_Account].[Communication3] AS [Communication3],
	[tbl_Account].[Communication3TypeID] AS [Communication3TypeID],
	[tbl_Account].[Communication4] AS [Communication4],
	[tbl_Account].[Communication4TypeID] AS [Communication4TypeID],
	[tbl_Account].[Communication5] AS [Communication5],
	[tbl_Account].[Communication5TypeID] AS [Communication5TypeID],
	[tbl_City].[Name] AS [CityName],
	[tbl_Account].[CityID] AS [CityID],
	[tbl_Account].[ZIP] AS [ZIP],
	[tbl_Contact].[Name] AS [PrimaryContactName],
	[tbl_Account].[PrimaryContactID] AS [PrimaryContactID],
	[tbl_Country].[Name] AS [CountryName],
	[tbl_Account].[CountryID] AS [CountryID],
	[tbl_State].[Name] AS [StateName],
	[tbl_Account].[StateID] AS [StateID],
	[tbl_Territory].[Name] AS [TerritoryName],
	[tbl_Account].[TerritoryID] AS [TerritoryID],
	[Owner].[Name] AS [OwnerName],
	[tbl_Account].[OwnerID] AS [OwnerID],
	[tbl_Account].[ActivityID] AS [ActivityID],
	[tbl_Activity].[Name] AS [ActivityName],
	[tbl_Account].[FieldID] AS [FieldID],
	[tbl_Field].[Name] AS [FieldName],
	[tbl_Account].[AccountTypeID] AS [AccountTypeID],
	[tbl_AccountType].[Name] AS [AccountTypeName],
	[tbl_AddressType].[Name] AS [AddressTypeName],
	[CommunicationType1].[Name] AS [Communication1TypeName],
	[CommunicationType2].[Name] AS [Communication2TypeName],
	[CommunicationType3].[Name] AS [Communication3TypeName],
	[CommunicationType4].[Name] AS [Communication4TypeName],
	[CommunicationType5].[Name] AS [Communication5TypeName],
	[tbl_Account].[Code] AS [Code],
	[tbl_Account].[TaxRegistrationCode] AS [TaxRegistrationCode],
	[tbl_Account].[CreatedOn] AS [CreatedOn],
	[tbl_Account].[CreatedByID] AS [CreatedByID],
	[CreatedBy].[Name] AS [CreatedByName],
	[tbl_Account].[ModifiedOn] AS [ModifiedOn],
	[tbl_Account].[ModifiedByID] AS [ModifiedByID],
	[ModifiedBy].[Name] AS [ModifiedByName],
	[tbl_Job].[NameOf] AS [JobNameOf],
	(SELECT SUM([Invoice].[Amount]) - SUM([Invoice].[PaymentAmount]) AS [DebtorAmount]	FROM [dbo].[tbl_IssueInApplication] AS [IssueInApplication]	LEFT OUTER JOIN [dbo].[vw_Issue] AS [Issue] ON [Issue].[ID] = [IssueInApplication].[IssueID] LEFT OUTER JOIN [dbo].[tbl_OfferingInApplication] AS [OfferingInApplication] ON [OfferingInApplication].[ID] = [IssueInApplication].[OfferingInApplicationID] LEFT OUTER JOIN [dbo].[vw_Application] AS [Application] ON [Application].[ID] = [OfferingInApplication].[ApplicationID] LEFT OUTER JOIN [dbo].[vw_Invoice] AS [Invoice] ON [Invoice].[ApplicationID] = [Application].[ID] WHERE([IssueInApplication].[IsPlaced] = @P1 AND [Application].[CustomerID] = [tbl_Account].[ID] AND [Issue].[StatusID] = @P2 AND ([Invoice].[BillStatusID] = @P3 OR [Invoice].[BillStatusID] = @P4))) AS [DebtorAmount]
FROM
	[dbo].[vw_Account] AS [tbl_Account]
LEFT OUTER JOIN
	[dbo].[vw_Contact] AS [tbl_Contact] ON [tbl_Contact].[ID] = [tbl_Account].[PrimaryContactID]
LEFT OUTER JOIN
	[dbo].[tbl_Territory] AS [tbl_Territory] ON [tbl_Territory].[ID] = [tbl_Account].[TerritoryID]
LEFT OUTER JOIN
	[dbo].[vw_Contact] AS [Owner] ON [Owner].[ID] = [tbl_Account].[OwnerID]
LEFT OUTER JOIN
	[dbo].[tbl_City] AS [tbl_City] ON [tbl_City].[ID] = [tbl_Account].[CityID]
LEFT OUTER JOIN
	[dbo].[tbl_State] AS [tbl_State] ON [tbl_State].[ID] = [tbl_Account].[StateID]
LEFT OUTER JOIN
	[dbo].[tbl_Country] AS [tbl_Country] ON [tbl_Country].[ID] = [tbl_Account].[CountryID]
LEFT OUTER JOIN
	[dbo].[tbl_Activity] AS [tbl_Activity] ON [tbl_Activity].[ID] = [tbl_Account].[ActivityID]
LEFT OUTER JOIN
	[dbo].[tbl_Field] AS [tbl_Field] ON [tbl_Field].[ID] = [tbl_Account].[FieldID]
LEFT OUTER JOIN
	[dbo].[tbl_AccountType] AS [tbl_AccountType] ON [tbl_AccountType].[ID] = [tbl_Account].[AccountTypeID]
LEFT OUTER JOIN
	[dbo].[vw_Contact] AS [CreatedBy] ON [CreatedBy].[ID] = [tbl_Account].[CreatedByID]
LEFT OUTER JOIN
	[dbo].[vw_Contact] AS [ModifiedBy] ON [ModifiedBy].[ID] = [tbl_Account].[ModifiedByID]
LEFT OUTER JOIN
	[dbo].[tbl_AddressType] AS [tbl_AddressType] ON [tbl_AddressType].[ID] = [tbl_Account].[AddressTypeID]
LEFT OUTER JOIN
	[dbo].[tbl_CommunicationType] AS [CommunicationType1] ON [CommunicationType1].[ID] = [tbl_Account].[Communication1TypeID]
LEFT OUTER JOIN
	[dbo].[tbl_CommunicationType] AS [CommunicationType2] ON [CommunicationType2].[ID] = [tbl_Account].[Communication2TypeID]
LEFT OUTER JOIN
	[dbo].[tbl_CommunicationType] AS [CommunicationType3] ON [CommunicationType3].[ID] = [tbl_Account].[Communication3TypeID]
LEFT OUTER JOIN
	[dbo].[tbl_CommunicationType] AS [CommunicationType4] ON [CommunicationType4].[ID] = [tbl_Account].[Communication4TypeID]
LEFT OUTER JOIN
	[dbo].[tbl_CommunicationType] AS [CommunicationType5] ON [CommunicationType5].[ID] = [tbl_Account].[Communication5TypeID]
LEFT OUTER JOIN
	[dbo].[tbl_Job] AS [tbl_Job] ON [tbl_Job].[ID] = [tbl_Contact].[JobID]
WHERE([tbl_Account].[ID] = @P5)',N'@P1 int,@P2 varchar(8000),@P3 varchar(8000),@P4 varchar(8000),@P5 varchar(8000)',1,'{E78E618C-956B-4D7E-9F6B-53955E31ADB5}','{89E2E62C-E2B0-47E6-A183-B774ED20CDE8}','{E64C1967-77EE-46DD-97D5-C0101067F6FA}','{A0EAB21C-2BB6-4B50-B4D0-90091A091736}'

Таблицы tbl_IssueInApplication и tbl_OfferingInApplication не администрируются по записям.
Скриншот ошибки в файле "Ошибка 1".

Другая ошибка - при открытии окна отображения связанных записей.Воспроизводится не только в контрагентах, а и в других разделах. Я сначала подумал, что это из за 3 пробелов в названии базы данных, но сделал копию без пробелов и ошибка не пропала(. Скриншот в файле "Ошибка 2".

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

Уже все нормально :smile:. Клиент просто в правах доступа к полям таблиц поставил уровень "Запрет" на поля, которые вытягивались в CustomSQL. Спасибо за помощь.
А ошибка при удалении связанных записей куда то сама исчезла :smile:

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

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

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

Заранее спасибо.

Версия 3.2.0.45.

У меня такой же вопрос

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

На сервере, в триггере.

Спасибо. Это даже лучше и проще :)

Войдите или зарегистрируйтесь, чтобы комментировать
Публикация

Нередко для пользователей было бы удобно отобразить в поле карточки задачи наименование процесса, по которому эта задача формируется.
Для реализации подобного функционала необходимо выполнить следующие действия:
1. Добавить новое поле для отображения процесса в следующие сервисы
 - tbl_Task
 - sq_Task
 - ds_Task
 - wnd_TaskEdit
2. Затем перейти в скрипт действия бизнес-процесса задач wa_TaskActionScript и найти обработчик события ws_TaskActionOnExecute. В этом обработчике события Вы увидите реализацию заполнения строк по умолчанию. Эти строки начинаются с DefaultValues.Add....
В этой части скрипта нужно добавить еще одну строку типа:

DefaultValues.Add('WorkflowName', ActionItem.ParentItems.ParentDiagram.Caption);

3. Сохраните внесенные изменения. Перезапустите рабочее приложение Terrasoft CRM и протестируйте работоспособность функционала.

Желаю удачи!

С уважением,
Мельникова Екатерина

Поделиться

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

а можно просто в sq_Task вытянуть из таблицы tbl_Workflow, которая присутствует уже в запросе, поле Name и не нужно добавлять новое поле в таблицу tbl_Task

Может таки лучше вытаскивать название сервиса, по которому стартовали БП, во время выполнения запроса, а не хранить его в задаче?
Upd: За Раловец Ольгой не поспеешь :) Но ее вариант возможно даже лучше.

есть отличие: в том варианте, что предложила Катя, вытягивается название сервиса диаграммы бизнес-процесса, то есть текущее значение поля Caption таблицы tbl_Service, а в моем случае показывается имя процесса, как он назывался в момент его запуска. То есть задачи, созданные двумя разными бизнес-процессами, но по одной диаграмме, могут иметь разные значения в этой колонке, если во время между их запусками Caption диаграммы был изменен

"Раловец Ольга" написал:есть отличие

Ну я как-бы догадался :)
Я имел ввиду, что Вы предложили вытаскивать из tbl_Workflow, а я из tbl_Service. И, возможно, Ваш вариант лучше.

я просто уточнила на всякий случай )

"Раловец Ольга" написал:можно просто в sq_Task вытянуть из таблицы tbl_Workflow

Это будет работать только для уже созданных задач БП. При первом открытии карточки (когда кнопка "Отмена" выключена) в этом поле будет пусто. Ведь запись в таблице фактически ещё не создана, не к чему делать join. В тот момент только из wa_TaskActionScript известно точно, что за процесс запустил эту задачу.

Войдите или зарегистрируйтесь, чтобы комментировать
Публикация

Нередко при работе с Terrasoft CRM возникает необходимость отправить своему сотруднику оповещение о задаче (или инциденте). В стандартном приложении Terrasoft CRM подобный функционал реализован при помощи предварительного создания шаблона e-mail по задаче.
Но не менее удобный функционал также может пригодиться: отправка оповещения о задаче во вложении к письму с возможностью написания своему коллеге личное сообщение в самом теле письма.
Постараюсь как можно более подробно описать алгоритм реализации подобного функционала.

Предлагаю воспользоваться функцией, описанной в scr_mailUtils CreateEmptyMessageWithAttachments. Ниже приведен пример непосредственного создания сообщения.

1. Создать файл MSWord с расширением dot. Особенность этого файла - его структура - это закладки (BookMarks), которые используются для автоматической замены значений, которые можно вытянуть из выборки данных необходимых для формирования шаблона. В прикрепленном файле высылаю пример - это таблица, в которую будут заноситься данные из конкретной выборки.

2. На необходимое действие нужно добавить функционал по созданию сообщения с вложением. Например, этот функционал можно добавить на какую-либо кнопку. Лучше всего воспользоваться базовой функцией CreateEmptyMessageWithAttachments. Ниже приведен пример ее использования, а также динамическое редактирование файла-шаблона.
Пример открытия файла:

 var WordRecord = OpenWordTemplate('C:\\TestReport.dot');

Пример создания выборки данных:

var Datasets = GetNewDictionary();
var Dataset = Services.GetNewItemByUSI('ds_Contact');
//здесь можно наложить необходимые фильтры
Dataset.Open();
AddDatasetToDictionaryByUSI(Datasets, 'Contacts', Dataset);
return Datasets;

Для заполнения документа-шаблона можно использовать функцию ReplaceWordBookmarks(WordInfo, Datasets). Как параметры ей передаются файл и созданный датасет. Только в этой функции созданный документ с заполненными значениями открывается, а его можно сохранить во временных документах на диске, а после прикрепления к письму удалять.

Пример непосредственного использования функции CreateEmptyMessageWithAttachments:

var Attachments = System.CreateObject('TSObjectLibrary.StringsList');
Attachments.Add(// необходимо указать полный путь к сохраненному документу);
CreateEmptyMessageWithAttachments(MailAddress, MailSubject, BodyFormat, CodePage, Importance, Attachments);
DeleteFilesFromStringsList(Attachments);

Также можно использовать не только сохраненный на диске файл, но и загружать его из библиотеки, используя базовую функцию поиска файла по коду FindFileInLibraryByCode(Code)

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

С уважением,
Мельникова Екатерина

Поделиться

0 комментариев
Войдите или зарегистрируйтесь, чтобы комментировать
Публикация

При перетягивании задачи в расписании, например, с сегодняшнего для на завтрашний, возникает необходимость также "сдвинуть" напоминание по этой задаче на такой же промежуток времени.
Привожу ниже работающий и протестированный пример подобной реализации.
Необходимо в scr_SchedulerArea в функции UpdateDatasetRecordByEvent прописать следующий код (новый код выделен):

var DataFields = Dataset.DataFields;
var StartDateDataField = DataFields.ItemsByName('StartDate');
var DueDateDataField = DataFields.ItemsByName('DueDate');
var OwnerIDDataField = DataFields.ItemsByName('OwnerID');
Dataset.Locate('ID', Event.ID);
var PriorStartDate = StartDateDataField.ValAsDateTime;
var PriorDueDate = DueDateDataField.ValAsDateTime;
if (!CheckTaskCovering(Dataset, OwnerIDDataField, Event.Start,
Event.Finish)) {
CancelChangeEvent(Event, PriorStartDate, PriorDueDate);
return;
}
Dataset.Edit();
strong>var RemindingToOwnerID = Dataset.Values('RemindingToOwnerID');
if (!IsEmptyValue(RemindingToOwnerID)) {
var uq_Remindings = GetSingleItemByCode('uq_Remindings', 'uq_RemindSingle');
var Parameters = uq_Remindings.Parameters;
var ColumnsValues = uq_Remindings.ColumnsValues;
SetParameterValue(Parameters, 'ID', RemindingToOwnerID);
ColumnsValues.ItemsByName('RemindTime').Value = Event.Start;
uq_Remindings.Execute();
}strong>
//Dataset.ValAsStr('Title') = Event.Caption;
StartDateDataField.ValAsDateTime = Event.Start;
DueDateDataField.ValAsDateTime = Event.Finish;
UpdateDuration(Dataset);
Dataset.Post();
UpdateEventColorsByDatasetRecord(Event, Dataset);

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

Желаю удачи!

С уважением,
Мельникова Екатерина

Поделиться

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

Здравствуйте! Пробовал использовать этот код, но ничего не получилось, выходят ошибки... и в конце концов в приложении в разделе расписание задачи вообще не отображаються,
может ли это быть связано с тем что у меня версия 3,3,1,а код для другой версии, пожалуйста поясните для какой версии подходит данный код?

"Мамажанов Марат Кадралдыкович" написал:но ничего не получилось, выходят ошибки

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

var DataFields = Dataset.DataFields;
var StartDateDataField = DataFields.ItemsByName('StartDate');
var DueDateDataField = DataFields.ItemsByName('DueDate');
var OwnerIDDataField = DataFields.ItemsByName('OwnerID');
Dataset.Locate('ID', Event.ID);
var PriorStartDate = StartDateDataField.ValAsDateTime;
var PriorDueDate = DueDateDataField.ValAsDateTime;
if (!CheckTaskCovering(Dataset,OwnerIDDataField,Event.Start,Event.Finish)) {
    CancelChangeEvent(Event, PriorStartDate, PriorDueDate);
    return;
}
Dataset.Edit();
var RemindingToOwnerID = Dataset.Values('RemindingToOwnerID');
if (!IsEmptyValue(RemindingToOwnerID)) {
    var uq_Remindings = GetSingleItemByCode('uq_Remindings', 'uq_RemindSingle');
    var Parameters = uq_Remindings.Parameters;
    var ColumnsValues = uq_Remindings.ColumnsValues;
    SetParameterValue(Parameters, 'ID', RemindingToOwnerID);
    ColumnsValues.ItemsByName('RemindTime').Value = Event.Start;
    uq_Remindings.Execute();
}
StartDateDataField.ValAsDateTime = Event.Start;
DueDateDataField.ValAsDateTime = Event.Finish;
UpdateDuration(Dataset);
Dataset.Post();
UpdateEventColorsByDatasetRecord(Event, Dataset);

Здравствуйте! Подставил данный код,ошибок нету, но дата напоминания не всегда обновляется при переносе задачи в расписании, но когда она все-таки обновляется, время начала напоминания становится равным времени начала задачи, но оно должно перетаскиваться ровно на стольно на сколько перетаскивается сама задача

Для реализации необходимого Вам функционала на Вашей версии приложения могу посоветовать заменить функционал строки

ColumnsValues.ItemsByName('RemindTime').Value = Event.Start;

на следующий:
- найти разницу между StartDateDataField.ValAsDateTime и Event.Start;
- найти запись из таблицы tbl_Remanding, значение поля RemindTime;
- добавить к нему разницу м/д StartDateDataField.ValAsDateTime и Event.Start;
- обновить запись в таблице tbl_Remanding.

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

function UpdateDatasetRecordByEvent(Dataset, Event) {

var DataFields = Dataset.DataFields;
var StartDateDataField = DataFields.ItemsByName('StartDate');
var DueDateDataField = DataFields.ItemsByName('DueDate');
var OwnerIDDataField = DataFields.ItemsByName('OwnerID');
Dataset.Locate('ID', Event.ID);
var PriorStartDate = StartDateDataField.ValAsDateTime;
var PriorDueDate = DueDateDataField.ValAsDateTime;
if (!CheckTaskCovering(Dataset,OwnerIDDataField,Event.Start,Event.Finish)) {
CancelChangeEvent(Event, PriorStartDate, PriorDueDate);
return;
}

Dataset.Edit();
var RemindingToOwnerID = Dataset.Values('RemindingToOwnerID');
var uq_Remindings = GetSingleItemByCode('uq_Remindings', 'uq_RemindSingle');
var ds_Remindings = dl_remLNK.dataset;
var Parameters = uq_Remindings.Parameters;
var ColumnsValues = uq_Remindings.ColumnsValues;
var ds_rem = ds_Remindings.DataFields.ItemsByName('RemindTime');
SetParameterValue(Parameters, 'ID', RemindingToOwnerID);
Event.Start;
uq_Remindings.Execute();

ds_Remindings.Close();
ApplyDatasetFilter(ds_Remindings, ID',RemindingToOwnerID, true);
ds_Remindings.Open();
ds_Remindings.edit();
ds_rem.ValAsDateTime = Event.Start;
ds_Remindings.post();

StartDateDataField.ValAsDateTime = Event.Start;
DueDateDataField.ValAsDateTime = Event.Finish;
UpdateDuration(Dataset);
Dataset.Post();
UpdateEventColorsByDatasetRecord(Event, Dataset);
}
я хотел фильтровать ds_Remindings.id по полю RemindingToOwnerID из первого датасета (ds_Task.RemindingToOwnerID), чтобы изменть напоминание связанное с текущим ответственным.
буду рад любым ответам

чем отличаются ds_Reminding и ds_Remindings какова роль каждого?

"Мамажанов Марат Кадралдыкович" написал:чем отличаются ds_Reminding и ds_Remindings какова роль каждого?

ds_Remindings соответствует всплывающему окну напоминаний. Вы можете посмотреть в соответствующем запросе на выборку sq_Remindings связи с таблицами, по записям которых появляются напоминания в этом окне.
ds_Reminding соответствует закладке "Напоминания" менеджера деталей.

Что касается Вашего кода, то проблема в не совсем корректном обновлении записей в таблице напоминаний. Например, нигде не указаны параметры для UpdateQuery.
Для решения проблемы рекомендую сделать следующим образом.
Сначала отфильтровать датасет напоминаний по нужной записи:

ds_Remindings.Close();
ApplyDatasetIDFilter(ds_Remindings, RemindingToOwnerID, true);
ds_Remindings.Open();

Затем записать в переменную описание напоминания (т.к. оно обязательно должно быть в UpdateQuery):

var RemindingDescription = ds_Remindings.Description;
if (IsEmptyValue(RemindingDescription)) {
                RemindingDescription = ‘Напоминание по задаче ’ + Dataset.Values(‘Title’);
}

Затем инициализация колонок UpdateQuery:

ColumnsValues.ItemsByName(‘Description’).Value = RemindingDescription;
ColumnsValues.ItemsByName(‘RemindTime’).Value = Event.Start;

Все это можно вставить между строками:

var ds_rem = ds_Remindings.DataFields.ItemsByName('RemindTime'); и SetParameterValue(Parameters, 'ID', RemindingToOwnerID);

Что касается блока:

ds_Remindings.Close();
ApplyDatasetFilter(ds_Remindings, ID',RemindingToOwnerID, true);
ds_Remindings.Open();
ds_Remindings.edit();
ds_rem.ValAsDateTime = Event.Start;
ds_Remindings.post();

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

Желаю удачи!

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

Инструмент импорт в интеграции. Не понятен один момент при импорте из экселя. Хочу импортировать таблицу задач с напоминаниями ответственному о выполнении и вижу: все даты как даты, т.е. с типом дата, а напоминания почему-то сделаны строковым типом.
В результате задачи без даты напоминания отлично импортируются, а задачи с проставленным полем напоминания не импортируются вовсе.

У меня такой же вопрос

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

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

Андрей, дело в том, что данные поля - ссылки на таблицу tbl_Reminding. Для того, чтобы они корректно отображались при настройке импорта нужно в таблицу tbl_Task добавить две связи (relation):

1. tbl_Task.RemindingToAuthorID -> tbl_Reminding.ID
2. tbl_Task.RemindingToOwnerID -> tbl_Reminding.ID

В результате Вы сможете настраивать импорт на деталь [Напоминания].

Terrasoft Support Team

Спасибо!

Войдите или зарегистрируйтесь, чтобы комментировать
Публикация

Иногда при постановке задачи возникает необходимость добавить к этой задаче еще десяток пользователей системы. Добавление вручную каждого пользователя на закладку "Контакты" занимает значительную часть времени пользователя. Полезным функционалом было бы создание новой кнопки "Добавить группу контактов".
Предлагаю вариант решения:
1. Вам необходимо в грид детали "Контакты" (менеджера деталей раздела "Задачи") добавить новую кнопку. Назвать ее, например, "Добавить группу пользователей" и присвоить Caption "AddUsersGroup".
2. Далее Вам необходимо реализовать две функции, которые потом будут вызываться в обработчике события нажатия на созданную кнопку.
2.1. Одна из функций должна реализовывать появление окна выбора существующих групп пользователей. Необходимая функция будет выглядеть примерно следующим образом:

function AddUsersGroup() {
var Dataset = GetSingleItemByCode('ds_Group', 'ContactInTaskGridArea');
var SearchFieldNames = 'Name';
var DisplayFieldNames = 'Name';
var KeyFieldName = 'ID';
var KeyValue = '';
var SearchFieldName = 'Name';
var SearchValue = '';
var NotifyObject = Self;
var Tag = 'SelectUsersGroupWindow';
var IsReadOnly = true;
ShowSelectDataWindow(Dataset, SearchFieldNames, DisplayFieldNames,
KeyFieldName, KeyValue, SearchFieldName, SearchValue, NotifyObject,
Tag, IsReadOnly);
}

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

function ProcessAddUsersGroup(Sender) {
var GroupID = Sender.Attributes('KeyValue');
if (!GroupID) {
return;
}
var UserSelectQuery = GetSingleItemByCode('sq_User',
'ContactInTaskGridArea');
var ContactInTaskDataset = GetSingleItemByCode('ds_ContactInTask',
'ContactInTaskGridArea');
ApplySelectQueryFilter(UserSelectQuery, 'GroupID', GroupID, true);
var UserDataset = UserSelectQuery.Open();
var TaskID = Self.Attributes('ParentItemID');
while (!UserDataset.IsEOF) {
ContactInTaskDataset.Append();
ContactInTaskDataset.Values('ID') = Connector.GenGUID();
ContactInTaskDataset.Values('TaskID') = TaskID;
ContactInTaskDataset.Values('ContactID') =
UserDataset.Values('UserContactID');
ContactInTaskDataset.Post();
UserDataset.GotoNext();
}
ContactInTaskDataset.Close();
UserDataset.Close();
}

3. Далее нужно в обработчике события OnClick созданной кнопки прописать вызов процедуры AddUsersGroup (вызова окна выбора групп).
function amiAddUsersGroupOnExecute(ActionMenuItem) {
AddUsersGroup();
}

4. Затем в обработчике события OnNotify грида менеджера деталей "Контакты" раздела "Задачи", прописать вызов фукнции ProcessAddUsersInGroup с необходимыми условиями.

function wnd_ContactInTaskGridAreaOnNotify(ScriptableService, Sender, Message,
Data) {
if (Message == MSG_OK) {
if (Sender.Tag == 'SelectUsersGroupWindow') {
ProcessAddUsersGroup(Sender);
}
RefreshDataset(BaseGridArea.GridDataset);
} else {
scr_BaseGridArea.wnd_BaseGridAreaOnNotify(ScriptableService, Sender,
Message, Data);
}
}

В прикрепленном файле высылаю пример текста доработанного сервиса.

Желаю удачи!

С уважением,
Мельникова Екатерина

Поделиться

0 комментариев
Войдите или зарегистрируйтесь, чтобы комментировать
Публикация

У многих пользователей системы Terrasoft CRM в разделе "Задачи" создано множество задач с различными типами. И вопрос зависимости
цвета задачи от ее типа является более нужным и востребованым, чем зависимость цвета задачи от состояния (как это реализовано в стандартной версии). Например, задачи с типом "Звонок" необходимо выделять синим цветом среди сотни задач сегодняшнего расписания, а задачу "Втреча" красным (для того, чтобы она не осталась незамеченной).

Предлагаю заменить функционал зависимости цвета от состояния на зависимость цвета от типа задачи следующим образом:
1. В таблицу tbl_TaskType довавляем поле Color с типом "Целое число".
2. Добавляем поле цвета в сервис sq_TaskType.
3. Добавляем целочисленное поле (IntegerDataField) в датасет ds_TaskType.
4. В карточку редактирования wnd_TaskTypeEdit добавляем контрол ColorBoxDataControl. Устанавливаем необходимые значения свойствам DatasetLink и DataFieldName.
5. Открываем запрос на выборку sq_Task. В этом запросе нужно изменить уже существующее поле StatusColor. А именно, сделать выборку поля Color из таблицы tbl_TaskType.
После сохранения всех внесенных изменений и перезапуска рабочего приложения, при выборе цвета в справочнике "Типы задач", созданные задачи будут подсвечиваться этим цветом.

Желаю удачи!

С уважением,
Мельникова Екатерина

Поделиться

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

Отлично! Я первый пользователь данной функциональности!
Ещё бы задачи с приоритетом "Срочно" или "Критично" всегда были наверху, в независимости от сортировки (опцию можно сделать отключаемой)

Вопрос.
Как прикрутить данную функциональность к разделу Контрагенты?
Проделал всё вышеописанное для собственного справочника, как теперь прикрутить цвета к гриду?

Пытаюсь сделать тоже самое для договоров по статусу...
"Подписан. Оплачен.", "Не подписан. Не оплачен."...
Проделал вышеизложенный алгоритм со справочником "Состояние договора" и с sq_Contract, ds_Contract.
Создал в scr_ContractsGridArea для grdData

function GetContractColorByDatasetRecord(Dataset) {
	var TextColor = Dataset.ValAsInt('Color');
	return TextColor;
}
 
// --------------
// Event handlers
// --------------
 
function grdDataOnGetRowDrawInfo(DataGrid, Color, TextColor, ImageName, Font) 
{
TextColor.Value = GetContractColorByDatasetRecord(BaseGridArea.GridDataset);
}

по аналогии с Задачами...
Но всё равно раскраска не происходит...

---
Конфигурация:
TSCRM 3.3.1.36
Firebird 2.0 (v.2.0.3.12981)

Александр, а HasCustomDraw в реестре включили?

уже включил...))
спасибо за подсказку, всё работает)

---
Конфигурация:
TSCRM 3.3.1.36
Firebird 2.0 (v.2.0.3.12981)

Отличная возможность + описание:twisted:
Счета, Документы, Договора - всё расскрасил!:wink:
Вот только при добавлении ColorBoxDataControl'а появляется сообщение "Разрушительный сбой!"...Никаких проблем после не возникало. Надеюсь так и останется просто плохим воспоминанием))

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

Ну, раскраска - это не мой креатив, а привычка тех, кто много лет работал еще с 2.8
Да и вообще, как говорят: "на вкус и цвет фломастеров нет":lol:
А вот с ошибкой непонятно:confused:

В родительских/подчиненных документах цветом не выделяется.
Внес нужные изменения в wmd_DocumentInDocumentGridAreaScript,
и не могу подобрать нужное значение в ф-ю GetContractColorByDatasetRecord() в обработчике grdDataOnGetRowDrawInfo.

Для реализации необходимого Вам функционала нужно выполнить следующие действия:
1. Сперва добавить поле Color в каждый из UNION sq_ChildDocument (из таблиц DocumentStatus, ContractStaus и BillStatus). Безусловно, предварительно нужно будет создать целочисленное поле Color в таблице, запросе, датасете и окне справочников "Состояния счета" и "Состояния договора".
2. Добавить целочисленное поле Color в ds_ChildDocument.
3. Добавить поле Color в каждый из UNION sq_ParentDocument.
4. Добавить целочисленное поле Color в ds_ParentDocument.
5. Установить для grdData в wnd_DocumentInDocumentGridArea свойство HasCustomDraw в true.
6. Прописать функцию и обработчик таким образом:

function GetDocumentColorByDatasetRecord(Dataset) {
        var TextColor = DocumentInDocument.Dataset.ValAsInt('Color');
        return TextColor;
}
 
// ----------------------------------------------------------------------------
// Event handlers
// ----------------------------------------------------------------------------
function grdDataOnGetRowDrawInfo(DataGrid, Color, TextColor, ImageName, Font) {
TextColor.Value = GetDocumentColorByDatasetRecord(DocumentInDocument.Dataset);	
}

7. Сохраните внесенные изменения. Перезапустите рабочее приложение Terrasoft CRM и протестируйте работоспособность функционала. В результате при указании документа, договора или счета - они будут подсвечиваться цветами, указанными в справочниках состояний.

Желаю удачи!

Так ведь и делал, только вот в вместо DocumentInDocument.Dataset писал DocumentInDocument.
А, и "Всегда выбирать в запросе":smile:
Спасибо!

"Мельникова Екатерина" написал:

"Швец Александр" написал:

я все проделал как описано - строки грида или текст окрашиваются нормально, но только если я вывожу колонку Color в гриде (в представлении gvMain грида определяю колонки и делаю colStatusColorgvMain видимой и доступной), но если сделать колонку невидимой для каждой строки грида выдается ошибка "Ошибка выполнения метода 'grdDataOnGetRowDrawInfo'. Поле 'Цвет' не активно «Call Stack»" и строки не окрашиваются.

Вопрос: Как сделать так чтоб колонка "Цвет" не выводилась и при этом корректно осуществлялась возможность раскрашивать строки грида?

Для колонки цвет сделайте "всегда выбирать в запросе" .

поменяйте функцию

function GetDocumentColorByDatasetRecord(Dataset) {
        var TextColor = DocumentInDocument.Dataset.ValAsInt('Color');
        return TextColor;
}

на такой вид

function GetDocumentColorByDatasetRecord(Dataset) {
        var TextColor = GetFieldValueFromDisabledField(Dataset, 'Color');
        return TextColor;
}

Или просто поставьте для поля Color галочку "Всегда выбирать в запросе" в сервисе запроса

Оба варианта ([1]Сделать колонку цвет "всегда выбирать в запросе" и [2]воспользоваться функцией GetFieldValueFromDisabledField()) работают - спасибо

Здравствуйте!
Помогите решить проблемы (Terrasoft 3.3.1.65).
1. Я раскрасил реестр (главные записи дерева), все работает.
Мне нужно забрать раскраску выделенной записи, то есть при изменение фокуса в реестре (при переходе на другую запись), данная запись выделяется стандартным оранжевым цветом. Думаю с рисунков будет понятнее:

2. Есть ли возможность при выборе ячейки (фокус или клик) вывести Caption?

Когда-то для реестра я включил прозрачность выделения (альфа = 128). Для дерева пока осталось по старому. Сегодня-завтра обязательно исправлю это недоразумение. Если не будет никаких нюансов -- то отпишусь какую версию бинарных файлов нужно взять.

Спасибо! Будем ждать! :smile:
Может заодно подправить DataGrid.SelectedColumn (всегда возвращает null)?

"genekogo" написал:Может заодно подправить DataGrid.SelectedColumn (всегда возвращает null)?

Исправить не обещаю -- но посмотрю обязательно.

"Александр Кравчук" написал:Когда-то для реестра я включил прозрачность выделения (альфа = 128). Для дерева пока осталось по старому. Сегодня-завтра обязательно исправлю это недоразумение. Если не будет никаких нюансов -- то отпишусь какую версию бинарных файлов нужно взять.

Поправил в 3.3.1.89 и 3.3.2.26:

"genekogo" написал:Может заодно подправить DataGrid.SelectedColumn (всегда возвращает null)?

Поправил также в 3.3.1.89 и 3.3.2.26.
Вот теперь я усну... :wink:

Саша! Низкий поклон и сладких снов!!!
:twisted:

--
www.it-sfera.com.ua

"genekogo" написал:Есть ли возможность при выборе ячейки (фокус или клик) вывести Caption?

Уточните, пожалуйста, какой Caption Вы имеете ввиду. Объясните, пожалуйста, на конкретном примере, поскольку не совсем очевидно, какой именно функционал Вам нужно реализовать.
Заранее спасибо за помощь.
Ожидаю ответа.

Мельникова Екатерина

Когда текст не вмещается в поле реестра появляется надпись (на рисунке поле «Заголовок»). Например, вместо надписи с текстом «Контроль оплаты счета (t)» я хотел бы отобразить надпись с текстом «Тестовая надпись» (и неважно вмещается текст в поле реестра или нет).
Есть ли возможность при выборе ячейки (фокус или клик) вывести свой Caption?

"genekogo" написал: Например, вместо надписи с текстом «Контроль оплаты счета (t)» я хотел бы отобразить надпись с текстом «Тестовая надпись».

Т.е. Вы хотите изменить хинт ячейки?

Да. :smile:

Никогда ни от кого не слышал такого пожелания. Для чего это может понадобится?

"Александр Кравчук" написал:Никогда ни от кого не слышал такого пожелания. Для чего это может понадобится?

А вот это я давно хотел увидеть в контролах - скажем подсказка-описание что за страшная информация скрывается в данном поле и каково ее назначение.

"Александр Кудряшов" написал:А вот это я давно хотел увидеть в контролах - скажем подсказка-описание что за страшная информация скрывается в данном поле и каково ее назначение.

Подсказка это одно, а это ведь хинт, который показывает не влезающий в ячейку текст.

У меня исследовательский интерес)) о полезном тоже можно - если ячейка отображает значение вычисляемого поля, можно было бы для менеджеров в этом хинте показывать, например, комментарии/разъяснение к этому результату...

Пример (из данной ветки форума): выводим в реестр информацию о продажах по дням

Когда наводим на ячейку, я хочу, что бы клиент увидел какую-то детализацию. Например, процентное наполнение дня... и т.д.

--
www.it-sfera.com.ua

если ячейка отображает значение вычисляемого поля, можно было бы для менеджеров в этом хинте показывать, например, комментарии/разъяснение к этому результату...

+1

--
www.it-sfera.com.ua

Ну что ж, заводите идею.

Вопрос такой, Подскажите пожалуйста как мне реализовать цветность в проектах?

1. В сервисе wnd_ProjectsGridArea в свойстве grdData необходимо найти свойство HasCustomDraw и присвоить ему значение true
2. В сервисе sq_Project для поля TypeID и активировать опцию "Всегда выбирать в запросе"
3. В сервисе wnd_ProjectGridArea найдите grdData и на закладке "Свойства" найдите свойство OnGetRowDrawInfo. Дважды кликните на правой части этого поля. В результате Вы автоматически перейдете в скрипт, в обработчик данного события.
4. В обработчике данного события необходим прописать следующее
function grdDataOnGetRowDrawInfo(DataGrid, Color, TextColor, ImageName, Font) {
// DefineRowDrawInfo(Color, TextColor, ImageName, Font);
var Dataset = dlData.Dataset;
var TypeID = Dataset.Value('TypeID');
switch (TypeID) {
case Type1:
TextColor.Value = clGreen;
break;
case Type2:
TextColor.Value = clRed;
break;
default:
TextColor.Value = clBlack;
break;
}
В данном скрипте вместо Type1, Type2, Type3 необходимо ставить ID типов инцидентов, которые предварительно нужно посмотреть в таблице tbl_ProjectType в используемой Вами СУБД
Что касается цветов, то Вы можете просмотреть перечень всех возможных цветов в сервисе scr_Const

А как раскрасить расписание? Не текст а event. подобие задач не предлагать - не получается

Здравствуйте! Посмотрите реализацию изменения цвета фона задач в расписании, в зависимости от состояния во вложенном файле.

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

Добрый день!

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

Создание задачи из скрипта проблем не вызывает, но каким образом (не используя хранимые процедуры и тригеры, а средствами JavaScript) отобрать в начале месяца всех контрагентов с нужным типом?

У меня такой же вопрос

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

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

Вы можете реализовать данную функциональность с помощью JOB, который будет выполнять действия или запускать процедуру в конкретные промежутки времени.
Данное решение подходит для версий приложения под MS SQL.
Как альтернативный вариант можете организовать проверку по дате на событие OnPrepare wnd_Main, если проверка возвращает значение, то применять фильтр (ранее созданный), т.е. проверка по дате будет работать каждый раз при запуске системы.

Terrasoft Support Team

Ага, каждый раз при запуске системы у каждого пользователя. А если два человека одновременно в начале месяца зайдут то, вообще весело будет.
JOB хороший вариант, но тогда не отработает логика, которая в скриптах прописана.
Я не уверен, но помоему при запуске tscrm.exe можно указать сервис окна, которое запустится вместо wnd_Main и пользователя\пароль. Если да, то рисуем новый сервис окна, в котором на OnPrepare создаем задачи и в конце закрываем окно. После в планировщик задач прописываем запуск tscrm.exe с правильными параметрами и ждем начала следующего месяца :)

Действительно хороший вариант, спасибо!

Вот пример запуска

TSCRM.exe /wnd=wnd_import /usr=Supervisor /pwd="" /cfg=tscrm

Добрый день!

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

Каким образом лучше организовать цикл перебора?

function wnd_BPOnPrepare(Window) {
var DatasetTask = Services.GetNewItemByUSI('ds_Task');
var DatasetAccount = Services.GetNewItemByUSI('ds_Account');
var AccountTypeID = '{CB403C3E-51C9-4117-8ADF-CEC787AE584C}'; //тип клиента = Клиент
ApplyDatasetFilter(DatasetAccount, 'AccountTypeID', AccountTypeID, true);
//в sq_Account создать фильтр сравнения с параметром AccountTypeID
DatasetAccount.Open();

DatasetTask.Append();

DatasetTask.Values('Title')='Связь'
DatasetTask.Values('PriorityID')= '{F6E5132C-BFC4-48E4-832B-0A60BBF6FC57}';
DatasetTask.Values('TypeID')= '{EE2F344B-BCE6-48A7-8813-20A4964DDE82}';
DatasetTask.Values('OwnerID')= DatasetAccount.Values('OwnerID');
DatasetTask.Values('StatusID')= '{9E289E42-9A0E-4A9C-A57F-049754310D95}';
DatasetTask.Values('AccountID')= DatasetAccount.Values('ID');
//DatasetTask.Values('StartDate')= GetTodayDate();
//DatasetTask.Values('DueDate')= AddDateDays(DateTime, 25)

DatasetTask.Post();
DatasetTask.Close();
DatasetAccount.Close();
}

Попробывал так:

function wnd_BPOnPrepare(Window) {
var DatasetTask = Services.GetNewItemByUSI('ds_Task');
var DatasetAccount = Services.GetNewItemByUSI('ds_Account');
var AccountTypeID = '{CB403C3E-51C9-4117-8ADF-CEC787AE584C}'; //тип клиента = Клиент
ApplyDatasetFilter(DatasetAccount, 'AccountTypeID', AccountTypeID, true);
//в sq_Account создать фильтр сравнения с параметром AccountTypeID
DatasetAccount.Open();

(!DatasetAccount.IsEOF)
DatasetTask.Append();

DatasetTask.Values('Title')='Связь'
DatasetTask.Values('PriorityID')= '{F6E5132C-BFC4-48E4-832B-0A60BBF6FC57}';
DatasetTask.Values('TypeID')= '{EE2F344B-BCE6-48A7-8813-20A4964DDE82}';
DatasetTask.Values('OwnerID')= DatasetAccount.Values('OwnerID');
DatasetTask.Values('StatusID')= '{9E289E42-9A0E-4A9C-A57F-049754310D95}';
DatasetTask.Values('AccountID')= DatasetAccount.Values('ID');
//DatasetTask.Values('StartDate')= GetTodayDate();
//DatasetTask.Values('DueDate')= AddDateDays(DateTime, 25)

DatasetTask.Post();
DatasetAccount.GotoNext();
}

DatasetTask.Close();
DatasetAccount.Close();
}

но создается 1242 задачи вместо 2-х

Я бы это сделал вот так

var AccountTypeID = '{CB403C3E-51C9-4117-8ADF-CEC787AE584C}';
var stNone = 0;
 
var AccountsDataset =  GetDetailSummary(
	'tbl_Account', 'AccountTypeID', AccountTypeID, 'ID', stNone);
var DatasetTask = Services.GetNewItemByUSI('ds_Task');
try {
	AccountsDataset.GoToFirst();
	while (!AccountsDataset.IsEOF) {
		DatasetTask.Append();
		DatasetTask.Values('Title')='Связь'
		DatasetTask.Values('PriorityID')= '{F6E5132C-BFC4-48E4-832B-0A60BBF6FC57}';
		DatasetTask.Values('TypeID')= '{EE2F344B-BCE6-48A7-8813-20A4964DDE82}';
		DatasetTask.Values('OwnerID')= DatasetAccount.Values('OwnerID');
		DatasetTask.Values('StatusID')= '{9E289E42-9A0E-4A9C-A57F-049754310D95}';
		DatasetTask.Values('AccountID')= DatasetAccount.Values('ID');
		//DatasetTask.Values('StartDate')= GetTodayDate();
		//DatasetTask.Values('DueDate')= AddDateDays(DateTime, 25)
		DatasetTask.Post();
		AccountsDataset.GotoNext();
	}
} finally {
	AccountsDataset.Close();
	DatasetTask.Close();
 
}

Вопрос снят, все получилось!

Войдите или зарегистрируйтесь, чтобы комментировать