При выполнении действия обновления структуры схемы произошла ошибка "Недопустимый объект. Для "dbo.qrtEstimate.FK31OIMXA98pJmJKZTu6AKjHWc3g" не разрешены расширенные свойства, либо объект не существует.", текст Sql сценария: "EXEC [dbo].[sp_addextendedproperty] N'TS.ActionType', N'ForeignKey', N'SCHEMA', N'dbo', N'TABLE', N'qrtEstimate', N'CONSTRAINT', N'FK31OIMXA98pJmJKZTu6AKjHWc3g'"

Нравится

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

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

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

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

 

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

Какие есть варианты решения данного вопроса и можно ли это сделать стандартными средствами предоставляемые Studio?

 

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

Нравится

4 комментария
Лучший ответ

Mykhailo Kozlenko,

Добрый день.

Можно в элементе 'Задание-сценарий' сформировать таблицу, которую нужно отправлять, и записать её в параметр бизнес-процесса. Например, я делала вот таким образом:

const string quote = "\"";
const string siteRef = "http://site_name";
 
var userConnection = Get<UserConnection>("UserConnection");
var softwareInventoryTableHTML = String.Empty;
 
var esqSoftwareInventory = new EntitySchemaQuery(userConnection.EntitySchemaManager, "SoftwareInventory");
esqSoftwareInventory.AddColumn("Id");
esqSoftwareInventory.AddColumn("Number");
esqSoftwareInventory.AddColumn("Software.Name");
esqSoftwareInventory.AddColumn("LicenseKey.Name");
var expirationDateColumn = esqSoftwareInventory.AddColumn("LicenseExpirationDate");
expirationDateColumn.OrderDirection = OrderDirection.Ascending;
expirationDateColumn.OrderPosition = 1;
esqSoftwareInventory.AddColumn("Equipment.Name");
esqSoftwareInventory.AddColumn("Equipment.Id");
esqSoftwareInventory.Filters.Add(esqSoftwareInventory.CreateFilterWithParameters(FilterComparisonType.Equal,
	"LicenseStatus", new Guid("CDD71003-D5BB-43E7-8E06-280FE40BEBF8")));
DateTime dueDate = DateTime.Today.AddMonths(2);
esqSoftwareInventory.Filters.Add(esqSoftwareInventory.CreateFilterWithParameters(FilterComparisonType.Less,
	"LicenseExpirationDate", dueDate));
var softwareInventories = esqSoftwareInventory.GetEntityCollection(userConnection);
if (softwareInventories.Count > 0)
{
	var htmlTableBuilder = new StringBuilder();
	htmlTableBuilder.AppendLine("<table border='1' width='100%' cellpadding='5'>");
	var headerSB = new StringBuilder();
	headerSB.Append("<tr>");
	string[] columnNames = { "Номер", "Программное обеспечение", "Лицензионный ключ", "Дата окончания лицензии",
		"Оборудование" };
	foreach (string columnName in columnNames)
	{
		headerSB.Append("<td>" + columnName + "</td>");
	}
    headerSB.Append("</tr>");
    htmlTableBuilder.AppendLine(headerSB.ToString());
	foreach (var softwareInventory in softwareInventories)
	{
		var rowSB = new StringBuilder();
		rowSB.Append("<tr>");
		string Number = softwareInventory.GetTypedColumnValue<string>("Number");
		Guid recordId = softwareInventory.GetTypedColumnValue<Guid>("Id1");
		string softwareInventoryRef = siteRef + "/0/Nui/ViewModule.aspx#CardModuleV2/SoftwareInventory1Page/edit/" +
			recordId.ToString();
		string inventoryNumberRef = "<a href=" + quote + softwareInventoryRef + quote +">" + Number + "</a>";
		rowSB.Append("<td width=\"44\">" + inventoryNumberRef + "</td>");
		rowSB.Append("<td width=\"120\">" + softwareInventory.GetTypedColumnValue<string>("Software_Name") + "</td>");
		string licenseKey = softwareInventory.GetTypedColumnValue<string>("LicenseKey_Name");
		int licenseKeyLength = licenseKey.Length;
		int indexStr = 8;
		if (licenseKeyLength <= 8)
		{
			indexStr = licenseKeyLength;
		}
		rowSB.Append("<td width=\"110\">" + licenseKey.Substring(0, indexStr) + "</td>");
		DateTime licenseExpirationDate = softwareInventory.GetTypedColumnValue<DateTime>(expirationDateColumn.Name);
		string licenseExpirationDateStr = "";
		if (licenseExpirationDate != DateTime.MinValue) {
			licenseExpirationDateStr = licenseExpirationDate.ToString("dd.MM.yyyy", CultureInfo.InvariantCulture);
		}
		rowSB.Append("<td width=\"83\">" + licenseExpirationDateStr + "</td>");
		rowSB.Append("<td width=\"106\">" +	softwareInventory.GetTypedColumnValue<string>("Equipment_Name") + "</td>");
		rowSB.Append("</tr>");
 
        htmlTableBuilder.AppendLine(rowSB.ToString());
	}
	htmlTableBuilder.AppendLine("</table>");	
	softwareInventoryTableHTML = htmlTableBuilder.ToString();
}
Set<string>("SoftwareInventoryTableHTML", softwareInventoryTableHTML);
return true;

А потом этот параметр бизнес-процесса использовать в элементе 'Отправить email' в качестве макроса:

Обратите внимание, по данному программному обеспечению истек срок действия лицензии либо истечет в ближайшее время.
Пожалуйста, актуализируйте в срм информацию по этому ПО:
[#Software inventory table#]
 
С уважением,
Системный администратор crm

 

P.S. В скрипте, приведенном выше, ещё и гиперссылки на карточки сущностей в срм формируются.

 

 

 

 

Добрый день.

 

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

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

Mykhailo Kozlenko,

Добрый день.

Можно в элементе 'Задание-сценарий' сформировать таблицу, которую нужно отправлять, и записать её в параметр бизнес-процесса. Например, я делала вот таким образом:

const string quote = "\"";
const string siteRef = "http://site_name";
 
var userConnection = Get<UserConnection>("UserConnection");
var softwareInventoryTableHTML = String.Empty;
 
var esqSoftwareInventory = new EntitySchemaQuery(userConnection.EntitySchemaManager, "SoftwareInventory");
esqSoftwareInventory.AddColumn("Id");
esqSoftwareInventory.AddColumn("Number");
esqSoftwareInventory.AddColumn("Software.Name");
esqSoftwareInventory.AddColumn("LicenseKey.Name");
var expirationDateColumn = esqSoftwareInventory.AddColumn("LicenseExpirationDate");
expirationDateColumn.OrderDirection = OrderDirection.Ascending;
expirationDateColumn.OrderPosition = 1;
esqSoftwareInventory.AddColumn("Equipment.Name");
esqSoftwareInventory.AddColumn("Equipment.Id");
esqSoftwareInventory.Filters.Add(esqSoftwareInventory.CreateFilterWithParameters(FilterComparisonType.Equal,
	"LicenseStatus", new Guid("CDD71003-D5BB-43E7-8E06-280FE40BEBF8")));
DateTime dueDate = DateTime.Today.AddMonths(2);
esqSoftwareInventory.Filters.Add(esqSoftwareInventory.CreateFilterWithParameters(FilterComparisonType.Less,
	"LicenseExpirationDate", dueDate));
var softwareInventories = esqSoftwareInventory.GetEntityCollection(userConnection);
if (softwareInventories.Count > 0)
{
	var htmlTableBuilder = new StringBuilder();
	htmlTableBuilder.AppendLine("<table border='1' width='100%' cellpadding='5'>");
	var headerSB = new StringBuilder();
	headerSB.Append("<tr>");
	string[] columnNames = { "Номер", "Программное обеспечение", "Лицензионный ключ", "Дата окончания лицензии",
		"Оборудование" };
	foreach (string columnName in columnNames)
	{
		headerSB.Append("<td>" + columnName + "</td>");
	}
    headerSB.Append("</tr>");
    htmlTableBuilder.AppendLine(headerSB.ToString());
	foreach (var softwareInventory in softwareInventories)
	{
		var rowSB = new StringBuilder();
		rowSB.Append("<tr>");
		string Number = softwareInventory.GetTypedColumnValue<string>("Number");
		Guid recordId = softwareInventory.GetTypedColumnValue<Guid>("Id1");
		string softwareInventoryRef = siteRef + "/0/Nui/ViewModule.aspx#CardModuleV2/SoftwareInventory1Page/edit/" +
			recordId.ToString();
		string inventoryNumberRef = "<a href=" + quote + softwareInventoryRef + quote +">" + Number + "</a>";
		rowSB.Append("<td width=\"44\">" + inventoryNumberRef + "</td>");
		rowSB.Append("<td width=\"120\">" + softwareInventory.GetTypedColumnValue<string>("Software_Name") + "</td>");
		string licenseKey = softwareInventory.GetTypedColumnValue<string>("LicenseKey_Name");
		int licenseKeyLength = licenseKey.Length;
		int indexStr = 8;
		if (licenseKeyLength <= 8)
		{
			indexStr = licenseKeyLength;
		}
		rowSB.Append("<td width=\"110\">" + licenseKey.Substring(0, indexStr) + "</td>");
		DateTime licenseExpirationDate = softwareInventory.GetTypedColumnValue<DateTime>(expirationDateColumn.Name);
		string licenseExpirationDateStr = "";
		if (licenseExpirationDate != DateTime.MinValue) {
			licenseExpirationDateStr = licenseExpirationDate.ToString("dd.MM.yyyy", CultureInfo.InvariantCulture);
		}
		rowSB.Append("<td width=\"83\">" + licenseExpirationDateStr + "</td>");
		rowSB.Append("<td width=\"106\">" +	softwareInventory.GetTypedColumnValue<string>("Equipment_Name") + "</td>");
		rowSB.Append("</tr>");
 
        htmlTableBuilder.AppendLine(rowSB.ToString());
	}
	htmlTableBuilder.AppendLine("</table>");	
	softwareInventoryTableHTML = htmlTableBuilder.ToString();
}
Set<string>("SoftwareInventoryTableHTML", softwareInventoryTableHTML);
return true;

А потом этот параметр бизнес-процесса использовать в элементе 'Отправить email' в качестве макроса:

Обратите внимание, по данному программному обеспечению истек срок действия лицензии либо истечет в ближайшее время.
Пожалуйста, актуализируйте в срм информацию по этому ПО:
[#Software inventory table#]
 
С уважением,
Системный администратор crm

 

P.S. В скрипте, приведенном выше, ещё и гиперссылки на карточки сущностей в срм формируются.

 

 

 

 

Я однажды делал подобное следующим образом:

в БП в элементе "Задание-сценарий" вычитывал в коллекцию какие-то значения.

После кодом формировал html-код в виде:

<table>

<tbody>

  <tr>

    <td >Номер</td>

    <td >Колонка 1</td>

    <td >Колонка 2</td>

  </tr>

  <tr>

    <td >1</td>

    <td >Значение 1</td>

    <td >Значение 2</td>

  </tr>

</tbody>

</table>

где Значение 1 и Значение 2 значения из коллекции.

После использовал элемент БП "Отправка письма", где в тело подсовывал html-код в виде строки.

После отправки получатель увидит заполненную html-таблицу

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

Здравствуйте, пытаюсь настроить автонумерацию по статье для 7.9(https://academy.terrasoft.ru/documents/technic-sdk/7-9/primer-ispolzovaniya-vstroennogo-processa-obekta-dobavlenie-avtonumeracii-k-polyu-stranicy), т.к. в свежей документации данный вопрос разбирается еще менее детально.

 

Удалось настроить присвоение номера на стороне клиента, но настройка через БП не работает.

 

В примере предлагается использовать обращение к Entity и UserTask1(АЛГОРИТМ РЕАЛИЗАЦИИ КЕЙСА НА СТОРОНЕ СЕРВЕРА, п.4.3):

UserTask1.EntitySchema = Entity.Schema;
return true;

К сожалению такое обращение к UserTask1 не работает совсем, говорит, что для данного контекста данный объект не определен(хотя в системе присутствуют коробочные БП, который используют такой синтаксис, вероятно проблема в том, что они компилируемые, а вот при интерпретировании такой синтаксис не работает)

Так же не работает обращение к Entity, он ругается с такой ошибкой: "An object reference is required for the non-static field, method or property 'Entity.Schema'".(Понятно в чем проблема, но не понятно, почему это раньше работало).

 

 

Я решил попробывать вот таким образом:

var esqRes = new EntitySchemaQuery(UserConnection.EntitySchemaManager, "UsrRequest");
Set("UserTask1.EntitySchema", esqRes.GetSchema());
return true;

 В данном случае это не сработало. Компиляцию проходит, но при выполнении  он падает с ошибкой: 

System.NotSupportedException: EntitySchema
 
   в Terrasoft.Core.Process.FlowEngineStateService.InternalSetValue[T](Guid processUId, String parameterPath, T value)
   в Terrasoft.Core.Process.FlowEngineStateService.Terrasoft.Core.Process.IInternalProcessParameterStore.InternalSetParameterValue[T](Guid processUId, String parameterPath, T value)
   в Terrasoft.Core.Process.ProcessInstanceParameterStore.SetParameterValue[TValue](String parameterPath, TValue value)
   в Terrasoft.Core.Process.ProcessInstanceParameterStore.SetParameterValue[TValue](ProcessSchemaParameter parameter, Guid schemaElementUId, TValue value)
   в Terrasoft.Core.Process.ProcessModel.SetParameterValue[T](FoundParameterData result, T value)
   в Terrasoft.Core.Process.ProcessModel.TrySetValue[T](ProcessSchema processSchema, String propertyPath, T value)
   в Terrasoft.Core.Process.ProcessModel.Set[T](String propertyPath, T value)
   в Terrasoft.Core.Process.RzdProcess_c91f2beRzdBaseZnoObject1MethodsWrapper.ScriptTask1Execute(ProcessExecutingContext context)
   в Terrasoft.Core.Process.ProcessFlowElement.ExecuteItem(ProcessExecutingContext context)
   в Terrasoft.Core.Process.ProcessFlowElement.Execute(ProcessExecutingContext context)

 

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

 

Т.к. в общем случае это работает: я смог передать таким образом текстовый параметр в "Выполнить действие процесса".

Подскажите, пожалуйста

Нравится

4 комментария
Лучший ответ

Думаю, в руководстве сказано про создание процесса в объекте, а не отдельно от него

А точно название пользовательского действия (в расширенном режиме) UserTask1?

 

Владимир Соколов, да.

Думаю, в руководстве сказано про создание процесса в объекте, а не отдельно от него

Владимир Соколов,

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

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

Подсмотрел реализацию onLookupResult в базовом коде

	onLookupResult: function(args) {
		var selectedRows = args.selectedRows;
		if (!selectedRows.isEmpty()) {

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

В этом случае selectedRows.isEmpty() всегда true. 

Как получить созданную запись?

Нравится

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

Добрый день, при нажатии кнопки "Добавить" из всплывающего окна (допустим при изменении поля с типом "Контакт") нас пересылает на страницу создания контакта. В этом случае мы не выбираем значение из списка и логично, что selectedRows.isEmpty() окажется true. Можете уточнить, для чего вам нужно получать созданную запись?

Дима Вовченко,

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

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

Алексей-Карягин,

Я немного ошибся в прошлом сообщении, 

selectedRows.isEmpty() окажется true в некоторых случаях. Например, поле "Ответственный", в которое можно записать только тот контакт, по которому существует пользователь системы. В этом случае после нажатия "Добавить" создастся новый контакт, но поскольку под него нет пользователя, то selectedRows окажется пустым и значение в поле не изменится. Если добавить новое поле справочник и уже в него добавлять запись, то selectedRows будет иметь значение созданного объекта.

Дима Вовченко, это, к сожалению, не ответ на мой вопрос.

Как вариант мне кажется сделать в ContactPageV2 в методе onSaved посыл сообщения о том что Контакт создан имеено таким способом, карточки подписчики будут получать сообщение и делать то что нужно.

Костыль, но думаю рабочий вариант.

Похоже у меня не правильная постановка вопроса. 

selectedRows.isEmpty() == true из-за фильтра, но фильтр надо как-то обойти.

Привожу пример для поля "Ответственный". Сам фильтр находится в схеме BaseFiltersGenerateModule, и вы можете попробовать его переопределить. Фильтр привязывается через атрибут на схема ContactPageV2:

 

"Owner": {
				dataValueType: Terrasoft.DataValueType.LOOKUP,
				lookupListConfig: {filter: BaseFiltersGenerateModule.OwnerFilter}
			},

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

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

Есть ли легитимная возможность определить источник вызова создания новой карточки?

Например, в контрагенте я выбираю Контакт, но могу нажать Добавить. В карточке контакта, в init или как-то еще можно определить Id контрагента, из которого вызвалось добавление?

Нравится

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

При открытии карточки контрагента, класть id контрагента в кэш. В карточке контакта считать значение из кэша.

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

Здравствуйте. Если не ошибаюсь, sandbox.id содержит гуид

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

Добрый день!

 

Подскажите, каким образом можно создать процесс по событию из новой конфигурации?

Раньше было:

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

 

а теперь просто автозаполняемое поле и никаких кнопок "Открыть процесс" и т.п.

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

 

Подскажите, как мне добавить событийный подпроцесс при создании новой записи.

Нравится

1 комментарий
Лучший ответ

В объекте слева выбираете События, в событиях выбираете нужны галочки. В верху есть кнопка Открыть процесс.

 

 

В объекте слева выбираете События, в событиях выбираете нужны галочки. В верху есть кнопка Открыть процесс.

 

 

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

Добрый день. Может кто-то подскажет почему не работает событие change (не вызывается присвоенный метод при изменении поля), если у поля тип RICH_TEXT, и можно ли это обойти как-то?

Нравится

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

Доброе утро.

 

Если Вы удостоверились, что проблема не связана с ошибками в программном коде, проверьте на последней актуальной версии (её можно развернуть прямо на сайте Террасофт) воспроизводится ли ошибка. Если на самой последней версии ошибка не вопроизведется, есть 2 пути - либо обновляться до последней версии, либо писать в службу поддержки и просить у них какой-то патч (если такой есть). Если ошибка воспроизведется и на последней версии, тогда также пишите в поддержку и просите у них разъяснений.

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

Коллеги существуют возможность поднятия сервиса Exchange Listener на Windows?

Нравится

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

Если сможете поставить docker на windows, то да.

Добрый день!

Хочу обратить внимание, что для продуктивных сайтов мы рекомендуем разворачивать  EXCHANGE LISTENER с использованием оркестратора Kubernetes и пакетного менеджера Helm.

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

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

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

Коллеги, замечено что для сервиса Exchange Listener необходим доступ в интернет, при его отсутствии статус сервиса на kubernetes становится ImagePullBackOff , как можно обойти эту проблему  использую exchangelistener-0.8.15

Нравится

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

Игорь Юрьевич, здравствуйте! 

 

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

 

Для решения проблемы вам необходимо обновить сервис на более новый. 

 

Начиная с версии 0.8.22 pullPolicy для образов изменена на IfNotPresent, и если образ будет закеширован во всех нодах kubernetes перезапуск\масштабирование\разворачивание сервиса не будет требовать доступа к docker hub. Если образа нет, то необходимо открыть доступ или перенести образ вручную на каждую ноду kubernetes.

 

Актуальная версия сервиса - 0.8.39.

Скачать можно на Академии - https://academy.terrasoft.ru/docs/user/ustanovka_i_administrirovanie/ra…

 

Хорошего дня!

Вильшанский Дмитрий

использовал 0.8.15

что понимается под  => если образ будет закеширован во всех нодах kubernetes, поясните пожалуйста 

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

Всем добрый день.

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

Нравится

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

Евгений, здравствуйте!



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

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



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

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