Помогите сделать запрос функции SQL из Исходного кода c возможностью записи результата и дальнейшим его использованием.

В sql запрос выглядит так :

SELECT  dbo.fn_dateadd_work ('minute', 20, defValues)

 

Нравится

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

Функцию с одним возвращаемым значением можно запустить так:

string number = "12345";
using (DBExecutor dbExecutor = userConnection.EnsureDBConnection()) {
	UserDefinedFunction userDefinedFunction = new UserDefinedFunction(userConnection, "fn_GetPhoneNumberSearchForm")
		.WithParameter("SourcePhoneNumber", number) as UserDefinedFunction;
	userDefinedFunction.PackageName = userConnection.DBEngine.SystemPackageName;
	userDefinedFunction.ReturnType = UserDefinedFunctionReturnType.Scalar;
	searchNumber = userDefinedFunction.ExecuteScalar<string>(dbExecutor);
}

Если же функция возвращает много значений:

using (DBExecutor dbExecutor = userConnection.EnsureDBConnection()) {
				UserDefinedFunction userDefinedFunction = new UserDefinedFunction(userConnection, "fn_GetFreeIntervalsForContactToDeadline")
					.WithParameter("ContactId", ContactId)
					.WithParameter("CalendarId", calendarId)
					.WithParameter("FromDate", userConnection.CurrentUser.GetCurrentDateTime())
					.WithParameter("Deadline", deadLineDate.ToString("yyyy-MM-dd HH:mm:ss"))
					.WithParameter("Offset", userConnection.CurrentUser.TimeZone.BaseUtcOffset.TotalMinutes) as UserDefinedFunction;
 
				userDefinedFunction.PackageName = userConnection.DBEngine.SystemPackageName;
				userDefinedFunction.ReturnType = UserDefinedFunctionReturnType.Table;
				using(IDataReader dataReader = userDefinedFunction.ExecuteReader(dbExecutor)) {
					while (dataReader.Read()) {
						DateTime startDate = dataReader.GetColumnValue<DateTime>("StartDate");
						DateTime endDate = dataReader.GetColumnValue<DateTime>("EndDate");
						//...
					}
				}
			}
string datepart = "day";
var defValues3 = "";
var defValues5 = "";
 
using (DBExecutor dbExecutor = userConnection.EnsureDBConnection()) {
                    UserDefinedFunction userDefinedFunction = new UserDefinedFunction(userConnection, "fn_dateadd_work ")
                            .WithParameter("datepart", datepart) 
            				.WithParameter("number", 3)
            				.WithParameter("date", defValues.StartDate)as UserDefinedFunction;
                    userDefinedFunction.PackageName = userConnection.DBEngine.SystemPackageName;
                    userDefinedFunction.ReturnType = UserDefinedFunctionReturnType.Scalar;
                    defValues3 = userDefinedFunction.ExecuteScalar<string>(dbExecutor);
            }
 

Выдает ошибку:
Exception Message: Не удалось найти столбец "dbo", определяемую пользователем функцию или агрегатную функцию "dbo.fn_dateadd_work ". Также возможно, имя является неоднозначным.
Exception Type: System.Data.SqlClient.SqlException
Exception Source: .Net SqlClient Data Provider

Функция Скалярная

Это значит, что такой функции у Вас в базе нет. Возможно, дело в пробеле в конце.

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

Это значит, что такой функции у Вас в базе нет. Возможно, дело в пробеле в конце.

			string datepart = "day";
			var defValues3 = "";
			var defValues5 = "";
            using (DBExecutor dbExecutor = userConnection.EnsureDBConnection()) {
            UserDefinedFunction userDefinedFunction = new UserDefinedFunction(userConnection, "fn_dateadd_work")
                .WithParameter("datepart", datepart) 
				.WithParameter("number", 3)
				.WithParameter("date", defValues.StartDate)as UserDefinedFunction;
            userDefinedFunction.PackageName = userConnection.DBEngine.SystemPackageName;
            userDefinedFunction.ReturnType = UserDefinedFunctionReturnType.Scalar;
            defValues3 = userDefinedFunction.ExecuteScalar<string>(dbExecutor);
			}

Убарала пробел, ошибка та же. Функция в Бд есть.
В инете пишут, что возможно фн табличная и к ней так и нужно обращаться...
http://www.cyberforum.ru/sql-server/thread735489.html

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

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

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

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


Спасибо, проблема в правах.

А можно как то в исходном коде реализовать такой вызов функции:

select * from dbo.fn_SomeFunctionName()  where someColumnName>2

Руслан, если через UserDefinedFunction такое нельзя, можно воспользоваться CustomQuery.

Хорошо, а через Select можно? Если да то как?

Пробовал так, не работает.

var select = (Select)new Select(_userConnection)
    .Column("Id")
    .From("fn_GetContactDescendantRoles")
    .Where("level")
    .IsEqual(Column.Parameter(1));
select.Parameters.Add("contact", new Guid("40445C52-FFD1-4DBA-94D8-127A7B29806A"));
select.Parameters.Add("parentRole", new Guid("CFB6F756-B740-44AD-A221-80C5E441EBF4"));

Выходит ошибка:

System.Data.SqlClient.SqlException: "Параметры функции "dbo.fn_GetContactDescendantRoles" не были предоставлены."

Руслан, я имел в виду не Select, а CustomQuery.

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

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

Я понял что вы имели ввиду, но мне не хочется делать приложение жестко привязанным к базе данных MSSQL. Ожидаю что использование класса Select оставит приложение "кроссплатформенным". Поэтому предположил что можно использовать Select как при обычном обращении к таблице, т.к. функция возвращает таблицу.

Руслан, в справке написано:

Класс Terrasoft.Core.DB.Select предназначен для построения запросов выборки записей из таблиц базы данных. 

Для работы с  функциями используют другой класс, UserDefinedFunction . Для произвольных запросов — CustomQuery.

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

Это все замечательно. Но в sql существует возможность выполнения такой конструкции:

select * from dbo.fn_SomeFunctionName()  where someColumnName&gt;2

Вы сказали что это не предусмотрено в классе UserDefinedFunction. Конечно моя функция не возвращает +100500 записей и можно было просто пробежаться по нужным в цикле, но я хочу задать условие на стороне сервера, чтобы он вернул только нужные по условию where. Вроде мелочь, но если количество запросов будет большое, то и сетевой трафик вырастет. В общем я за оптимизацию. Есть ли возможность в будущем расширить функционал данного класса?

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

Завёл идею, но не уверен, что до неё скоро доберутся.

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

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

Добрый день.
Подскажите пожалуйста как в 5 версии системы отправить письмо с прикрепленными файлами из БП.
Интересует именно как прикрепить к письму файлы?
В БП использую элементы(действия) "Добавление данных", затем "Действие процесса"(Отправить сообщение), в котором указываю Id созданной ранее записи.
Таким образом письмо отправляется на почту. А как туда еще и файлы прикрепить?

Нравится

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

Антонина, действие «Отправить сообщение» должно уметь отправлять письмо со вложениями. Оно берёт файлы из таблицы детали «ActivityFile», привязанные к этой активности. См. функцию «GetActivityAttachments» внутри действия.

А чтобы прикрепить файлы на эту деталь, нужно выполнить код, аналогичный функции «CopyFiltes» со страницы «EmailEditPage». Ещё один пример, где прикрепляется сгенерированный файл отчёта, приведен здесь, но этот код под 7.Х, могут быть некоторые отличия.

То есть Вы создаёте в БП новую активность типа «email», сохраняете её, добавляете ей на деталь файлы, а затем вызываете действие отправки.

А если мне нужно отправить файлы которые не прикреплены к активности, а прикреплены например к заявкам? Вроде бы как дублировать эти файлы в активности не хотелось бы.

Текущая логика берёт файлы с детали у активности. В принципе, если критично место в базе, можно как-то доработать логику функции «GetActivityAttachments» действия «Отправить сообщение», чтобы оно при определённых условиях брало содержимое файлов из другого места.

Ещё один возможный подход: реально в БД в таблице «ActivityFile» (и ей подобных) хранится только ссылка на активность и ссылка на общую таблицу файлов всех разделов, куда попадают название, размер, содержимое файла. Можно попробовать у записи о файле в другом разделе брать значение «FileId» и подставлять в новую запись о файле активности. Но при этом потребуются переделки в структуре таблицы, подобные тем, что описаны в этой теме, поскольку сейчас Id файла — первичный ключ.

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

Столкнулся со следующей проблемой в BPMOnline ServiceDesk 5.4:
- Необходимо в Аналитике сделать ПОЧАСОВОЙ график регистрации инцидентов.

Но при настройке графика для поля "Дата/время" предлагается только форматы "Год, Месяц, Неделя, День". Соответственно вопрос каким образом добавить формат "Час"??

Нравится

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

Решил проблему сам путем добавления в объект SysDateTimeFormat следующей строчки:

insert into SysDateTimeFormat(Name,Code) values('Час','Hour')

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

Здравствуйте.
Нахожусь в разделе. Открыла деталь, на которой сделала кнопку.
Мне нужно, чтобы В зависимости от параметров, которые есть у записи раздела, кнопка на детали выводилась или не выводилась.

Каким образом мне получить Id выделенной(активной) записи раздела на странице реестра детали?

Нравится

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

this.get("ActiveRow").
альтернативный вариант - var row = this.getActiveRow()

"Варфоломеев Данила" написал:

this.get("ActiveRow").

альтернативный вариант - var row = this.getActiveRow()


Таким образом выдает ошибку при компиляции, что нету get'а.

"Чемезова Антонина" написал:Таким образом выдает ошибку при компиляции, что нету get'а.

Прошу прощения, поздно заметил, что вопрос относится к BPMonline 5.x. Мой вариант применим к 7.x

Вы можете получить Id текущей записи в реестре на детали, а затем получить значение поля, по которому идёт связь с разделом. Например, если деталь в разделе контактов, то поле в объекте детали ContactId.

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

Вы можете получить Id текущей записи в реестре на детали, а затем получить значение поля, по которому идёт связь с разделом. Например, если деталь в разделе контактов, то поле в объекте детали ContactId.


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

В таком случае стоит привязывать логику не к детали, а к основному разделу.
В странице раздела (BaseModulePage) есть событие GridActiveRowChanged, которое срабатывает при смене записи в основном реестре и к нему привязывается обновление детали. Вы можете в своём разделе добавить на него дополнительную логику.

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

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

А как из основного раздела скрыть видимость кнопки детали?

Аналогично наложению фильтров на детали, через detailPageContainer.FindPageControlByName. Как получается detailPageContainer, см. в коде базовой страницы раздела логику обновления деталей.

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

Аналогично наложению фильтров на детали, через detailPageContainer.FindPageControlByName.


Можете подсказать, примерчик где-то в системе есть похожий?

Да, в нескольких местах так получают DataSource со страницы детали. Посмотрите поиском по конфигурации. Думаю, получить кнопку можно так же.

	var detailDataSource = (detailPageContainer.FindPageControlByName("DataSource")) as Terrasoft.UI.WebControls.Controls.DataSource;
	if (detailDataSource != null) {

"Зверев Александр" написал:Да, в нескольких местах так получают DataSource со страницы детали. Посмотрите поиском по конфигурации. Думаю, получить кнопку можно так же.

Александр, так кнопка же не содержится в DataSource детали. Она находится на странице детали. Как к ней добраться? на Page.Print.SetVisible(false); ругается.

var detailsTabPanel = Page.PageContainer.FindPageControlByName("DetailsTabPanel") as Terrasoft.UI.WebControls.Controls.TabPanel;
var detailsTab = detailsTabPanel.Tabs[detailsTabPanel.ActiveTabIndex];
var detailPageContainer = detailsTab.Items[0] as PageContainer;
var detailDataSource = (detailPageContainer.FindPageControlByName("DataSource")) as Terrasoft.UI.WebControls.Controls.DataSource;
var page = Page.AspPage as Terrasoft.UI.WebControls.Page;
	 if (detailDataSource == null) {
			Page.Print.SetVisible(false);
}

Аналогично. DataSuorce и эта Ваша кнопка — два компонента на одной странице.Указывайте в FindPageControlByName название компонента с кнопкой. Тип значения при этом также будет другой.

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

В странице реестра на компоненте DataSource довольно много событий. Возможно, какое-то из них.
Для эксперимента можно добавить в каждое из них, подходящее по смыслу, обработчик, поставить там breakpoint-ы и посмотреть, кто будет позже всех.
events

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

Добрый день.
Пишу: Если в справочном поле OriginEdit выбрали значение с ИД ceb02546-179e-4c11-b959-df488f53f799 , то справочное поле SRTypeEdit должно автоматически заполниться значением с ИД dc284b1f-be17-402b-9134-1836d4b1f21f . Не пойму , как написать на С#, не получатся так: (Guid)Page.SRTypeEdit.Value = SRTypeId;

Guid sost = new Guid("ceb02546-179e-4c11-b959-df488f53f799");
var sost1 = (Guid)Page.OriginEdit.Value;

var SRTypeId = new Guid("dc284b1f-be17-402b-9134-1836d4b1f21f");

string s = "ИД Задачи ";
if (sost1 == sost)
{
Page.SymptomsEdit.Value = s;
//(Guid)Page.SRTypeEdit.Value = SRTypeId;

}

return true;

Нравится

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

Для установки значения в справочное поле используется метод SetValueAndText.
Где найти примеры его использования — вы знаете.

Подскажите, как вытащить наименование SRType, зная SRTypeId?

Page.SRTypeEdit.SetColumnValueAndText(SRTypeId, SRType.Name);

Для этого есть функция GetEntityTypedColumnValue.

В карточке Инцидента в обработчике события (по факту выбора в поле OriginEdit выбрали значение с ИД ceb02546-179e-4c11-b959-df488f53f799) мне нужно, чтобы автоматически заполнилось поле SRTypeEdit значением, соответствующим ИД dc284b1f-be17-402b-9134-1836d4b1f21f. Пишу:

Guid dir = new Guid("ceb02546-179e-4c11-b959-df488f53f799");
var dir1 = (Guid)Page.OriginEdit.Value;

Guid SRTypeId = new Guid("dc284b1f-be17-402b-9134-1836d4b1f21f");
string SRTypeName = Terrasoft.Configuration.CommonUtilities.GetEntityTypedColumnValue(UserConnection, "Incident", "SRType", SRTypeId);

string s = "ИД Задачи ";
if (dir1 == dir)
{
Page.SymptomsEdit.Value = s;
Page.DataSource.ActiveRow.SetColumnValue("SRTypeId", SRTypeName);

}

return true;

Опубликовывает без ошибок. При выборе в карточке Инцидента в поле OriginEdit - ошибка :

Date: 25.01.2017 11:54:53
Date (UTC): 25.01.2017 8:54:53

Exception Message: Элемент с именем "Incident" не найден
Exception Type: Terrasoft.Common.ItemNotFoundException
Exception Source: Terrasoft.Core

Пожалуйста, подскажите, как исправить эту ошибку. Заранее спасибо

Это значит, что в базе нет таблицы с указанным именем.

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

Это значит, что в базе нет таблицы с указанным именем.


заменила Incident на ServiceRequest

в итоге - Опубликовывает без ошибок. Но при выборе в карточке Инцидента в поле OriginEdit - ничего не подставилось

Используйте отладку.

а нужно использовать SetColumnValue или SetValueAndText ? Если SetValueAndText - то пишет ошибку "не содержит определение для SetValueAndText . Пропущена директива using или ссылка на сборку"

Посмотрите в конфигурации готовые примеры использования этой функции. Сделайте полностью аналогично.

Guid dir = new Guid("ceb02546-179e-4c11-b959-df488f53f799");
var dir1 = (Guid)Page.OriginEdit.Value;

Guid SRTypeId = new Guid("dc284b1f-be17-402b-9134-1836d4b1f21f");
string SRTypeName = Terrasoft.Configuration.CommonUtilities.GetEntityTypedColumnValue(UserConnection, "ServiceRequest", "SRType", SRTypeId);

string s = "ИД Задачи ";
if (dir1 == dir)
{
Page.SymptomsEdit.Value = s;
Page.DataSource.ActiveRow.SetColumnValue("SRTypeId", SRTypeId);
Page.SRTypeEdit.SetValueAndText(SRTypeId, SRTypeName);

}

return true;

В итоге: опубликовало без ошибок. Но: когда я открываю карточку Инцидента и выбирают определенный Origin (происхождение инцидента), то в поле авт-ки не подтягивается нужный мне SRType (Тип обращения). А вот при сохранении этой карточки Инцидента и открытии ее на изменение - в поле SRType отображается нужный мне тип обращения. Для сравнения - если я беру другой Origin , сохраняю карточку Инцидента и открываю ее вновь - поле SRType не заполнено. Т.е., в принципе-то, алгоритм работает. Подскажите, пожалуйста, как сделать так, чтобы поле SRType заполнялось сразу же при выборе опред.Origin, а не после повторного открытия карточки. Заранее спасибо

Попробуйте провести отладку и посмотреть, какое значение в какую переменную попадает.
Затем исправьте ошибки в своём коде.

Не попадает в переменную string SRTypeName.

Не пойму, как взять именно наименование SRTypeName, если известен SRTypeId?

Вам нужно правильно воспользоваться функцией GetEntityTypedColumnValue. Примеры неоднократно опубликованы на этом сайте.

У меня все получилось:

Guid dir = new Guid("ceb02546-179e-4c11-b959-df488f53f799");
var dir1 = (Guid)Page.OriginEdit.Value;

Guid SRTypeId = new Guid("dc284b1f-be17-402b-9134-1836d4b1f21f");

var SRTypeName =Terrasoft.Configuration.CommonUtilities.GetEntityTypedColumnValue(UserConnection, "SRType", "Name", SRTypeId);

string s = "ИД Задачи ";
if (dir1 == dir)
{
Page.SymptomsEdit.Value = s;

Page.DataSource.ActiveRow.SetColumnValue("SRTypeId", SRTypeId);
Page.SRTypeEdit.SetValueAndText(SRTypeId, SRTypeName);

}

return true;

И что?

все подставляется, как надо.

Мне кажется, что и без строки, где вызываете SetColumnValue, будет работать.

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

Добрый день

В Е-мейл активности при нажатии на кнопку нужно добавить в HtmlBody этой Е-мейл-активности имя контакта текущего пользователя. Пишу скрипт:

string html = Page.DataSource.ActiveRow.GetTypedColumnValue("HtmlBody");

Guid contactId = UserConnection.CurrentUser.ContactId; //id контакта текущего пользователя
string contactName = UserConnection.CurrentUser.ContactName; //имя контакта текущего пользователя

string str = String.Concat(contactName, html);

var defValuesId = Entity.GetTypedColumnValue("ActivityId");
var defValues = ? // что здесь нужно написать?

defValues.Add("HtmlBody", str);

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

Нравится

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

Что именно написать в коде, зависит от того, что Вы хотите получить.
Если вбить в поиск по конфигурации «var defValues =», получим:

var defValues = new Dictionary <string, object>();

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

А если я хочу заменить содержимое HtmlBody в открытом док-те нажатием на опред.кнопку, правильно ли я использую var defValues ? Заранее спасибо.

Получилось и работает:

string html = Page.DataSource.ActiveRow.GetTypedColumnValue("HtmlBody");

Guid contactId = UserConnection.CurrentUser.ContactId; //id контакта текущего пользователя
string contactName = UserConnection.CurrentUser.ContactName; //имя контакта текущего пользователя

string str = String.Concat(contactName, html);

Page.DataSource.ActiveRow.SetColumnValue("HtmlBody", str);

return true;

Если поставить теги
, то в BPMOnline вид текста в е-мейл активности отображается с учетом переносов на новую строчку. Но, отправив на эл.адрес эту е-мейл, вижу: в Qutlook в полученном электронном письме текст слился в одну строчку. Подскажите, пожалуйста, как можно этого избежать? Заранее спасибо

Полный текст:
string html = Page.DataSource.ActiveRow.GetTypedColumnValue("HtmlBody");

Guid contactId = UserConnection.CurrentUser.ContactId; //id контакта текущего пользователя
string contactName = UserConnection.CurrentUser.ContactName; //имя контакта текущего пользователя
string contactmail = Terrasoft.Configuration.CommonUtilities.GetEntityTypedColumnValue(UserConnection, "Contact", "Email", contactId);
string contactdol = Terrasoft.Configuration.CommonUtilities.GetEntityTypedColumnValue(UserConnection, "Contact", "JobTitle", contactId);
string contactphone = Terrasoft.Configuration.CommonUtilities.GetEntityTypedColumnValue(UserConnection, "Contact", "Phone", contactId);
string contactMobilePhone = Terrasoft.Configuration.CommonUtilities.GetEntityTypedColumnValue(UserConnection, "Contact", "MobilePhone", contactId);

string s6 = "Добрый день"+"


С уважением,
"+ contactName + "
" + contactdol + "
Департамент информационных технологий
АО «ДКС»"+ "

Tel :"+ contactphone + ", " + contactMobilePhone + "
e-mail :"+ contactmail +" , www.dkc.ru";

string str = String.Concat(s6, html);

Page.DataSource.ActiveRow.SetColumnValue("HtmlBody", str);

Погодите...
Если html содержит картинку, то текст вываливается в одну строчку, а если html нет картинок, то текст прописывается как надо. Подскажите, пжста, есть ли решение, как уйти от этой проблемы? Заранее спасибо

Погодите...
Если html содержит картинку, то текст вываливается в одну строчку, а если html нет картинок, то текст прописывается как надо. Подскажите, пжста, есть ли решение, как уйти от этой проблемы? Заранее спасибо

Перенос строк в письме формата HTML делается так же, как и в других HTML-страницах: при помощи тега

<br>

или более сложных конструкций вёрстки. Обычные переносы строк в тексте по Enter при этом не учитываются.

Если html содержит картинку, то текст вываливается в одну строчку, а если html нет картинок, то текст прописывается как надо. Подскажите, пжста, есть ли решение, как уйти от этой проблемы? Заранее спасибо

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

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

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

Здравствуйте.
Использую версию системы 5.4.1.1034

Создала новую кнопку в реестре документов, у этой кнопки создала список. Т.е. при нажатии на кнопку вываливается список. При нажатии на один из пунктов запускается процесс, который описан в дизайнере процесса карточки.
Мне нужно, чтобы этот список менялся, т.е. какие то пункты скрывались, а какие то отображались, при смене активной строки реестра. Если быть конкретнее, то в зависимости от вида документа, который сейчас выбран в реестре, должен быть отображен тот или иной список пунктов меню.

Я так понимаю, что логику нужно накладывать на событие DataSourceActiveRowChanged.
А дальше что делать?
Пробовала удалять меню кодом, потом подпихивать новые пункты и скриптом и просто хиденом:

var button = Page.Print;
var menu = button.Menu;
menu.RemoveAll();
               
var esquery = new EntitySchemaQuery(UserConnection.EntitySchemaManager, Page.DataSource.Schema.Name);
esquery.AddAllSchemaColumns();
var entity = esquery.GetEntity(UserConnection, SelectedNodePrimaryColumnValue);

if(entity == null){
        //button.Hidden = false;
        return true;
}

Guid DocumentId = entity.GetTypedColumnValueGuid>("Id");

Guid documentCategoryId = entity.GetTypedColumnValueGuid>("CategoryId");
Guid DocumentCategory_SPokupatelem = (Guid)Core.Configuration.SysSettings.GetValue(UserConnection, "DocumentCategory_SPokupatelem");


if(documentCategoryId == DocumentCategory_SPokupatelem) {
string script = string.Empty;
var menuItem1 = Page.MenuItem1;
var menuItem2 = Page.MenuItem2;
menu.Add(menuItem1);
menu.Add(menuItem2);   
                script = string.Format("window.{0} = {1};\n", menuItem1.ClientID, menuItem1.GenerateControlScript(true, null));
                script += string.Format("{0}.getMenu().addItem(window.{1});\n", button.ClientID, menuItem1.ClientID);
                //script += string.Format("{0}.getMenu().addSeparator();\n", button.ClientID);
       
                                script = string.Format("window.{0} = {1};\n", menuItem2.ClientID, menuItem2.GenerateControlScript(true, null));
                                script += string.Format("{0}.getMenu().addItem(window.{1});\n", button.ClientID, menuItem2.ClientID);
Page.AddScript(script);
                Page.MenuItem1.Hidden = false;
                Page.MenuItem2.Hidden = false;
                Page.MenuItem3.Hidden = false;
                Page.MenuItem4.Hidden = false;
                Page.MenuItem5.Hidden = false;
                Page.MenuItem6.Hidden = false;
                Page.MenuItem7.Hidden = false;
}

Нравится

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

Антонина, а если заранее добавить все возможные пункты меню, а потом лишние скрывать при помощи свойства «Hidden»?

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

var esquery = new EntitySchemaQuery(UserConnection.EntitySchemaManager, Page.DataSource.Schema.Name);
esquery.AddAllSchemaColumns();
var entity = esquery.GetEntity(UserConnection, SelectedNodePrimaryColumnValue);
 
if(entity == null){
	Page.Print.Hidden = false;
	return true;
}
 
Guid DocumentId = entity.GetTypedColumnValue<Guid>("Id");
 
Guid documentCategoryId = entity.GetTypedColumnValue<Guid>("CategoryId");
Guid DocumentCategory_SPokupatelem = (Guid)Core.Configuration.SysSettings.GetValue(UserConnection, "DocumentCategory_SPokupatelem");
 
 
if(documentCategoryId == DocumentCategory_SPokupatelem) {
		Page.MenuItem1.Hidden = true;
		Page.MenuItem2.Hidden = true;
		Page.MenuItem3.Hidden = true;
		Page.MenuItem4.Hidden = true;
		Page.MenuItem5.Hidden = true;
		Page.MenuItem6.Hidden = true;
		Page.MenuItem7.Hidden = true;
}	
else{
		Page.NewItem.Hidden = true;
		Page.New2Item.Hidden = true;
}

А если попробовать скрывать не через свойство «.Hidden», а методом «.SetVisible(false)»?

Александр, добрый день.
И метод «.Hidden» и метод «.SetVisible(false)» в данном случае работают одинаково, т.е. скрывают/отображают пункты меню при необходимости. Но делают они это при загрузке страницы реестра.
Т.е. когда я открываю раздел документооборот, загружается страница реестра и отображает тот список меню кнопки, в соответствии с первой строкой реестра, т.к. она выделена. Затем же при переходе на другие строки реестра, меню кнопки не обновляется.

Получается тут 2 варианта:
- либо я использую не тот сигнал. А использую я DataSourceActiveRowChanged, вроде как все правильно.
- либо меню кнопки не перестраивается при смене активной позиции в реестре. Значит вопрос как это делать?
Или я не правильно мыслю?

Антонина, ваше первое предположение можно проверить, установив отладчик в скрипте-обработчике события. Если при смене строки срабатывает — сигнал тот.

По второму, посмотрел в кодах всех конфигураций, которые были под рукой, и нигде сходу не нашёл такого примера работы с пунктами меню. Возможно, действительно есть какие-то ограничения. Кроме двух ранее использованных способов, можно попробовать скрывать ещё в клиентском скрипте по ClientId, вызывая там «.setVisible(false)» (с маленькой «s»).

Если и это не даст результатов, придётся использовать другие подходы в интерфейсе, вроде отдельного диалогового окна со списком пунктов или заглушек при попытке запустить неподходящий пункт меню. Кстати, если менять не видимость, а доступность пунктов, не реагирует так же само?

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

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

Нравится

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

Тут комплекс задач..
- получить ID нужного обращения, сгенерировать ссылку для перехода с участием этого ID;
- создать письмо на основе шаблонного html тела + подставить в него ссылку для перехода вместо заглушки, отправить письмо;
- поймать обработать событие перехода по ссылке из письма пользователем.

Тем навскидку и поиском не припомню, чтобы комплексно это обсуждалось...

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

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

Есть справочник «Шаблоны e-mail сообщений», есть действие БП «Обработать шаблон письма с макросами», которое с ним работает.

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

Добрый день
Сделала изменение в процессе отправки ответа по отмене Инцидента, а именно: создана новый параметр (строка), далее, ч/з формулу определила ее значение как "тело шаблона" + "заметки в инциденте", после чего в новой активности с типом е-мейл в колонке html указала значение этого нового параметра.
В итоге - все получилось, в окне е-мейл активности на отправку ответа об отмене Инцидента вижу нужные данные. НО: если заметки в инциденте содержали какую-либо картинку, то при сохранении этой е-мейл-активности картинка не подтягивается на вкладку "Файлы" (как, напр., при копировании е-мейл активности). Думаю, что в связи с этим в письме, полученном Заявителем, эта картинка не будет открываться. Помогите, пожалуйста, как исправить этот момент. Заранее спасибо

Нравится

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

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

Вы можете обратиться в Terrasoft и заказать такую доработку. Маловероятно, что кто-то тут прочитает Вашу постановку и начнёт её реализовывать, чтобы потом Вам выслать.

Приятной работы!

Мария, я уже ценю Ваш юмор!

Спасибо!

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

Здравствуйте.
Подскажите, пожалуйста, как можно решить проблему с веб-сервисом в bpmonline 5.4.
При компиляции ошибки: "Имя типа или пространства имен "ServiceModel" отсутствует в пространстве имен "System" (пропущена ссылка на сборку?)"
И соответственно: "Не удалось найти имя типа или пространства имен "ServiceContract" (пропущена директива using или ссылка на сборку?)"
Не использую EntityDataService.svc, так как нужен сервис, доступный без авторизации.

Нравится

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

Елена, возможно, Вы что-то неправильно заполнили в Using нового сервиса. См. как написан любой готовый сервис в конфигурации, например, CardService в коробке Loyalty 5.3.
Также см. статью.

Александр, спасибо. Помогло копирование библиотек в папку bin и добавление ссылок.

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