В конфигурации отправка описана в скрипте scr_TaskUtils в функции function SendTaskEmailToContact(TaskDataset, AddressList)

Таким образом, Вам необходимо доработать функцию следующим образом:

function SendTaskEmailToContact(TaskDataset, AddressList) {
         if (GetDatasetFieldValue(TaskDataset, 'CycleTaskParamID')) {
                   var TemplateID = GetSystemParameterValueEx('CycleTaskEmailByContactTemplateID');
         } else {
                   var TemplateID = GetSystemParameterValueEx('TaskEmailByContactTemplateID');
         }
         if (IsEmptyGUID(TemplateID)) {
                   ShowErrorDialog(FormatStr(SystemParameterIsEmptyError,
                            'TaskEmailByContactTemplateID'));
                   return;
         }
         var ID = TaskDataset.Values('ID');
                   
         var FileName = System.CreateObject('TSObjectLibrary.Value'); //создаем объект файл
         FileName.Value = 'C:\\Test.rtf'                                             //определяем путь хранения временного файла
         TaskDataset.DataFields('Description').SaveToFile(FileName.Value);  //сохраняем описание в файл
         var Attachments = new Array(FileName.Value);                           //определяем, что данный файл будет аттачем
         
         var Service = Services.GetSingleItemByUSI('scr_MailUtils');
         Service.ScriptControl.CodeObject.SendEmailByTemplate(TemplateID,
                   {RecordID: ID, Address: AddressList, AutoSend: true,
                   SkipQueryAddresses: true, Attachments: Attachments}); //в этой строке добавлены аттачи
}

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

1. Откройте sq_Task и добавьте новую колонку Description:

img125
img126

Сохраните и закройте запрос.

2. Откройте датасет ds_Task и добавьте в него колонку типа большой бинарный объект:

img127
img128

Сохраните и закройте датасет.

3. Откройте scr_TaskUtils и внесите изменения в функцию отправки письма. Перезапустите клиент. Результат будет выглядеть следующим образом:

img129

Нравится

Поделиться

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

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

Нравится

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

Вот часть скрипта, которая выполняется по кнопке "Связать элементы" (обработчик действия amiConnectElementsOnExecute в скрипте wnd_ProjectGanttAreaScript):

	var SelectedIDsArray = GetSelectedItemsIDsArray();
	if (SelectedIDsArray.length == 0) {
		ShowWarningDialog("Элементы не выбраны");
		return;
	}
	ConnectProjectElementsArray(Self, SelectedIDsArray, AreaObject);
	RefreshDataset(dlData.Dataset);

Основная функция связки - ConnectProjectElementsArray, которая вызывает AddProjectDependence из скрипта scr_ProjectDependenceUtils.

Пересчёт элементов выполняется функцией DoElementCalculation скрипта scr_ProjectElementLibrary. Посмотрите её реализацию, а также реализацию функций DoChildElementsCalculation и DoParentElementCalculation.

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

Статья посвящена отдельным проблемам управления процессом.
Тезис: Управление процессом возможно при осуществлении связи контроля и коррекции.
Проблема: Технологичный контроль (и как следствие коррекция) в некоторых случаях затруднителен.
Решение:

  1. Перенос функций контроля на участников процесса (взаимный контроль)
  2. Нормализуется не задача, а результат, к которому она приводит.
  3. Мотивация привязвается к результатам работы

Регуляция процесса и задачи контроля

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

Проще всего контролировать сущности, которые сами по себе являются индикаторами:
• Итоговые результаты работы (объем продаж, трудозатраты),
• Показатели хода процесса (количество встреч, звонков)
• Факты наступления событий (поступление платежа, выполнение задачи).

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

Ограничение механизмов контроля.

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

Проблема уникальности задачи.

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

Проблема изменчивости критериев.

Во-вторых, некоторые критерии неоднозначны в своей динамике, иными словами, меняются в ходе выполнения задачи. Самый простой пример это критерий своевременности. Мы можем ввести регламентный срок выполнения, но в силу вышеописанных причин норматив, может быть, не применим. Дело даже не, столько в том, что могут измениться фактические трудозатраты, сколько в том, что своевременность, часто зависит от факторов, на которые мы повлиять не можем. У каждого продавца, наверное, были случаи, когда презентация коммерческого предложения планировалась через неделю, а клиент сообщил, что ее необходимо провести через три дня. Таким образом, своевременность определяется не нормативом или плановым сроком, а наступлением некоторого события.
Если взять пример с расчетом, то требования к его содержанию также, могут меняться в процессе подготовки (например, требования к уровню детализации задач).

Описанные затруднения, наглядно иллюстрируют причины, по которым многие компании не могут реализовать технологичность процесса. Отсутствие механизмов контроля и регуляции вынуждает менеджера вникать в детали процесса или даже отдельной задачи, оценивать качество решения и регулировать дальнейшую работу. Этому собственно и посвящены многие человеко-часы планерок и совещаний. Несмотря на то, что такие затраты уменьшают количество времени затрачиваемого на выполнение производственных задач, отказаться от них, в подобной ситуации, нельзя, поскольку возникает угроза сбоя всего процесса.
Самое удивительное в этой задаче то, что отдельные элементы решения успешно применяются в практике каждой компании. Вы, наверное, обратили внимание, что для одной из ролей в организации свойственны именно такие уникальные и изменчивые задачи. Да, это роль руководителя (менеджера). Поэтому предлагаю рассматривать работу сотрудников решающих подобные задачи как работу руководителей.

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

  1. Заинтересованность в результате
  2. Необъективность контроля

Проблема заинтересованности

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

Таким образом, выход здесь в том, что мотивация должна быть направлена не на выполнение частной задачи, а на уровень выше, а именно на достижение результатов того шага процесса который зависит от качества решения этой задачи.
При таком подходе РП, при подготовке расчета, должен будет задаться вопросом, что и как необходимо сделать для успеха коммерческого предложения. Правильно, то есть, исходя из требования к своевременности, расставлять приоритеты в своей работе, корректно контролировать качество и при необходимости прилагать дополнительные усилия. Сотрудник, который не замотивирован на результат, не только ставит заниженные цели своей работы, но и часто ложные.
Поэтому задача руководителя сводится к выделению таких «неизмеримых» задач и привязки мотивации в них к получаемому результату. Только такая заинтересованность будет являться гарантией, того что все возможное для достижения цели будет выполнено.

В тоже время, сотрудники, ориентированные на высокий результат, как правило, ожидают и требуют, чтобы и их коллеги также разделили подобное стремление, что является мощным двигателем развития команды. В противном случае возможна ситуация, когда один сотрудник «болеет» за результат, но не встречает поддержки (а причины всегда есть) у своих коллег. Тогда кроме возникновения рисков процесса, существенно снижается мотивация этого сотрудника, что в конечном итоге не может не привести к снижению качества его работы и, как следствие, к упущенным возможностям.

Проблема контроля и ответственности

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

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

Разумеется, что эти критерии представляют собой некие приближения. Объективность достигается за счет того, что одного сотрудника оценивает не один человек, а все кто с ним работает, использует результаты его труда. Кроме этого если раньше исполнитель был ответственен перед руководителем, то теперь он отвечает перед теми, кто кровно заинтересован в его результатах. Привязка значимой части бонусирования к такой оценке резко повышает качество взаимной работы.

Риски и решения:

В этом предложении есть риск, возможных злоупотреблений. К счастью, его можно предусмотреть:
Во-первых, можно скрыть проставляемые оценоки, для того чтобы избежать влияния «авторитетов».
Во-вторых, руководитель в приватном разговоре может запросить объяснения поставленной оценке и в случае если она покажется ему не объективной - отклонить ее.
Таким образом, дружба против кого-то, посредством организованного выставления оценок, не будет возможна и руководитель не потеряет контроль над ситуацией.
В тоже время, и это важно, контроль оценок периодически может осуществлять и руководитель на уровень выше. Это особенно полезно в случае если команда не до конца доверяет своему непосредственному руководителю или он еще не получил должный авторитет. Подразумеваемая эскалация визирования оценок, обеспечит максимальную веру в справедливость оценки.

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

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

Нравится

Поделиться

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

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

Согласен с Инной. Не хватает тезисов и разбивки статьи на части. Статья интересная, но "ниасилил".

Спасибо. Я пока только разбираюсь с тем как писать посты. То что вы видите - черновик. Обязательно подправлю.

Хочу сделать дополнение к теме индикаторов контроля.

Часто все KPI и критерии оценки разрабатываются "внутри" отдела. Мне кажется правильнее если внутри отдела будут формироваться только критерии эффективности (производительности), а критерии оценки качества будут разрабатываться исключительно "потребителями" работы отдела.

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

Юра,
Естественно выработка критериев качества - двухсторонний процесс, исполнитель всегда имеет право отклонить необоснованные (или недостижимые) требования. Но интерес потребителя первичен - он предъявляет исходные требования к качеству работы.

Потребитель дает исполнителю цель его работы и критерии оценки качества. Исполнитель строит свои процессы исходя из этих требований и разрабатывает критерии эффективности (но не качества).

Если критерии эффективности и качества разрабатывает исполнитель, то мы рискуем получить такую систему оценок, которая на уровне KPI дает "хорошую" картину, а фактическая ситуация иная. Т.е. система оценок имеет риск исказить реальную ситуацию.

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

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

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

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