Пытаюсь вызывать alert('Hello') на каждой странице. Получилось пока только на конкретной странице создав замещающий клиентский модуль и наследуясь от SalesEnterpriseSoftkey_ENU. Как можно сделать этот алерт на всех страницах,  включая авторизацию и другие?

Нравится

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

Андрей, можно вообще добавить свой скрипт в системную настройку GoogleTagManagerScript («Скрипт для Google Tag Manager»), так он будет срабатывать после логина или при загрузке страницы в новой вкладке.

При помощи этого способа встроили в 7.Х голосовалку от Hotjar:

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

Добрый день, Коллеги!

Есть ли какие-то инструкции, как по аналогии с пакетом Тим и Энтерпрайз в разделах Продажи, создать подобную воронку по своему разделу. 

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

П.С. Понимаю, что кодом :)

Нравится

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

Да, странно, что нигде не опубликовали инструкции, как доработать программу до более дорогого продукта. Логика воронки реализована во многих схемах со словом «Funnel» в названии.

 

Как вариант, кроме отдельного блока итогов «Воронка» есть ещё одноимённый режим графика.

chapter_analytics_chart_element_list_mode.png

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

Подскажите, пожалуйста, как можно запустить процесс на объекте ПОСЛЕ исполнения процессов, определенных в родительском объекте?

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

Нравится

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

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

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

Нигрескул Алексей пишет:

Вы можете использовать событийный слой и там разрабатывать обработку данных объекта

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

Однако, в данном случае поле Code (заполняется в процессе объекта на OnSaved) оказывается пустым.



 

[EntityEventListener(SchemaName = "Account")] 
public class UsrAccountEntityEventListener : BaseEntityEventListener
 {
  public override void OnSaved(object sender, EntityAfterEventArgs e) {
    base.OnSaved(sender, e);
 
    var entity = (Entity) sender;
    var userConnection = entity.UserConnection;
 
    string accountCode = entity.GetTypedColumnValue<string>("Code");
 
    throw new Exception(entity.Schema.Name + " " + accountCode);

 

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

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

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

выяснили, что процесс выполняется первым, но в событийном слое у  entity нет тех значений, которые установились в процессе: https://community.terrasoft.ua/questions/poluchenie-znacheniy-v-sobytiy…

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

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

Пытаюсь развернуть конфигурацию. Несколько раз перепроверил строку подключения, настройку веб-сокетов и т.д., не могу развернуть конфигурацию уже несколько дней с ошибкой "Недопустимое имя объекта "dbo.SysSettings".".

Может кто-нибудь подсказать, где по крайней мере искать проблему?

 

Лог прилагаю:

 

Недопустимое имя объекта "dbo.SysSettings".

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.



Exception Details: System.Data.SqlClient.SqlException: Недопустимое имя объекта "dbo.SysSettings".



Source Error:

 

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.



Stack Trace:

 

[SqlException (0x80131904): Недопустимое имя объекта "dbo.SysSettings".]
   System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) +3329424
   System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) +334
   System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) +4289
   System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() +89
   System.Data.SqlClient.SqlDataReader.get_MetaData() +101
   System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted) +624
   System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest) +3392
   System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry) +725
   System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) +84
   System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) +312
   Polly.<>c__DisplayClass119_0`1.<Execute>b__0(Context ctx, CancellationToken ct) +23
   Polly.<>c__DisplayClass129_0`1.<ExecuteInternal>b__0(Context ctx, CancellationToken ct) +22
   Polly.<>c__DisplayClass103_0.<NoOp>b__1(Context ctx, CancellationToken ct) +18
   Polly.NoOp.NoOpEngine.Implementation(Func`3 action, Context context, CancellationToken cancellationToken) +17
   Polly.<>c.<NoOp>b__103_0(Action`2 action, Context context, CancellationToken cancellationToken) +105
   Polly.Policy.ExecuteInternal(Func`3 action, Context context, CancellationToken cancellationToken) +156
   Polly.Policy.Execute(Func`3 action, Context context, CancellationToken cancellationToken) +113
   Polly.Policy.Execute(Func`1 action) +211
   Terrasoft.DB.MSSql.MSSqlExecutor.FailoverExecute(DbCommand command, Func`1 func) +96
   Terrasoft.Core.DB.DBExecutor.FailoverExecuteReader(DbCommand command, Func`1 func) +55
   Terrasoft.Core.DB.DBExecutor.ExecuteCommand(Func`2 commandExecutionCallback, String sqlText, QueryParameterCollection queryParameters, CancellationToken cancellationToken) +622
   Terrasoft.Core.DB.DBExecutor.InternalExecuteReader(String sqlText, QueryParameterCollection queryParameters, CommandBehavior behavior, CancellationToken cancellationToken) +142
   Terrasoft.Core.DB.DBExecutor.InternalExecuteReader(String sqlText, QueryParameterCollection queryParameters) +25
   Terrasoft.Core.SystemSettings.DbLoaders.SysSettingsMetaDataLoader.Load(String key) +72
   Terrasoft.Core.SystemSettings.DataProvider.DbItem`2.TryGet(TKey key, TValue& value) +13
   Terrasoft.Core.SystemSettings.Objects.SysSettingsMetaData.Fetch(String code) +103
   Terrasoft.Core.SystemSettings.Objects.SysSettingsMetaData.Fetch(UserConnection userConnection, String code) +54
   Terrasoft.Core.SystemSettings.SysSettingsEngine.TryGetDefaultSettingsValue(String code, Object& value) +29
   Terrasoft.Core.UserConnection.GetDefaultTimeZone(TimeZoneInfo timeZone) +84
   Terrasoft.Core.SystemUserConnection.InitializeCurrentUser(String userName, TimeZoneInfo timeZone, String clientIP, String agent, Boolean needRegisterSessionStart) +384
   Terrasoft.Core.SingleInstanceSystemUserConnectionProvider.Initialize(Boolean doLogin) +124
   Terrasoft.Core.AppConnection.InitializeSystemUserConnection(ConfigurationSection schemaManagerProviderConfigurationSection) +54
   Terrasoft.Core.AppConnection.Initialize() +493
   Terrasoft.WebApp.Loader.Global.InitializeAppConnection() +152
   Terrasoft.WebApp.Loader.Global.Application_Start(Object sender, EventArgs e) +233
 
[HttpException (0x80004005): Недопустимое имя объекта "dbo.SysSettings".]
   System.Web.HttpApplicationFactory.EnsureAppStartCalledForIntegratedMode(HttpContext context, HttpApplication app) +546
   System.Web.HttpApplication.RegisterEventSubscriptionsWithIIS(IntPtr appContext, HttpContext context, MethodInfo[] handlers) +171
   System.Web.HttpApplication.InitSpecial(HttpApplicationState state, MethodInfo[] handlers, IntPtr appContext, HttpContext context) +173
   System.Web.HttpApplicationFactory.GetSpecialApplicationInstance(IntPtr appContext, HttpContext context) +255
   System.Web.Hosting.PipelineRuntime.InitializeApplication(IntPtr appContext) +347
 
[HttpException (0x80004005): Недопустимое имя объекта "dbo.SysSettings".]
   System.Web.HttpRuntime.FirstRequestInit(HttpContext context) +552
   System.Web.HttpRuntime.EnsureFirstRequestInit(HttpContext context) +122
   System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context) +737

Нравится

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

Неверное название базы данных указали. Ради эксперимента изменил в  ConnectionStrings.config рабочей системы название БД (Initial Catalog) на master и получил ту же ошибку. Нужно указывать имя БД, которую вы развернули из бекапа.

Неверное название базы данных указали. Ради эксперимента изменил в  ConnectionStrings.config рабочей системы название БД (Initial Catalog) на master и получил ту же ошибку. Нужно указывать имя БД, которую вы развернули из бекапа.

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

Добрый день, Коллеги!

Добавил скрипт в бп, который формирует и прикрепляет к email печатную форму.

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

Была похожая тема, но ответа там не нашел. Была версия что UserConnection не передается. Ниже скрин элемента из бп и ошибки.

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

 

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

 

Если плохо видно код, то вот:

var reportService = new Terrasoft.Configuration.ReportService.ReportService();

var PrintableId= Get("PrintableId");

var ObjectId = Get("ObjectId");

var ConvertToPdf = false;

var AddActivityId = Get("AddActivityId");

var AttachmentType = Get("AttachmentType");

Terrasoft.Configuration.ReportService.ReportData report = reportService.GenerateMSWordReport(

    (PrintableId.ToString()), ObjectId.ToString(), ConvertToPdf);

var entity = UserConnection.EntitySchemaManager.GetInstanceByName("ActivityFile");

var fileEntity = entity.CreateEntity(UserConnection);

fileEntity.SetDefColumnValues();

fileEntity.SetColumnValue("ActivityId", AddActivityId);

fileEntity.SetColumnValue("TypeId", AttachmentType);

fileEntity.SetColumnValue("Name", "Новый отчет.docx");

fileEntity.SetColumnValue("Data", report.Data);

fileEntity.Save();

return true; 

Нравится

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

Измените первую строчку на передачу UserConnection:

var reportService = new Terrasoft.Configuration.ReportService.ReportService(UserConnection);

Измените первую строчку на передачу UserConnection:

var reportService = new Terrasoft.Configuration.ReportService.ReportService(UserConnection);

Помогло, спасибо большое!)

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

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



А как сделать полноценный раздел в этом случае?

Или необходимо дублировать уже имеющийся объект?Изображение удалено.

Нравится

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

Удалось разобраться, опишу шаги:

 

1. Создать отдельный пакет (с нужной зависимостью), в котором будет создан раздел 

(если в объекте не установлена колонка для отображения, то придётся создавать ещё один пакет, в котором указать колонку для нужного объекта)



2. Установить системную настройку CurrentPackageId на созданный в п.1



3. Установить пустое значение в системной настройке SchemaNamePrefix



4. Создать раздел на основе существующего объекта, используя Мастер разделов



5. Вернуть обратно системные настройки CurrentPackageId и SchemaNamePrefix



6. Если для объекта уже существовала страница редактирования, то теперь их будет две. Можно найти соответствующие записи

select * from SysModuleEdit 
where  SysModuleEntityId IN 
    (Select Id from SysModuleEntity 
                where SysEntitySchemaUId = (SELECT Uid FROM SysSchema WHERE Name = 'AccountBillingInfo' AND ExtendParent = 0))



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

update SysModuleEdit 
set CardSchemaUId = '8790CD96-F7D5-4ADC-931A-8248CEF25EC0'
where CardSchemaUId = '625E1D4C-BC26-4872-B76E-267C473ECDCC'

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

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

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

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



Но на самом деле, это нормальный путь, если представить, что пакет в пункте 1 - это стандартный пакет Creatio



Ну, и надеюсь, что R&D читают community и учтут этот кейс

Да, если нужно визирование в разделе, то его тоже надо делать в пункте 4

Спасибо за обратную связь. Команда разработки ответила, что учтёт этот кейс в будущих релизах.

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

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

Нравится

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

Добрый день.

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

Ниже привожу пример подобной фильтрации:

if (project &amp;&amp; project.value) {
	var filterGroup = this.Terrasoft.createFilterGroup();
	var subFilters = Terrasoft.createFilterGroup();
    subFilters.addItem(Terrasoft.createColumnFilterWithParameter(
		Terrasoft.ComparisonType.EQUAL, "EWBProject", project.value));
	filterGroup.addItem(this.Terrasoft.createExistsFilter("[BTProjectDisease:BTDiseaseType:Id].Id",
		subFilters));
	var subFilters1 = Terrasoft.createFilterGroup();
	subFilters1.addItem(Terrasoft.createColumnFilterWithParameter(
		Terrasoft.ComparisonType.EQUAL, "ProjectSpecification", this.get("MasterRecordId")));
	filterGroup.addItem(this.Terrasoft.createNotExistsFilter(" 
       [SpecificationByDiseaseType:DiseaseType:Id].Id",	subFilters1));
}

В результате в базу данных сформируется такой SQL-запрос:

SELECT
	[BTDiseaseType].[Id] [Id],
	[BTDiseaseType].[Name] [Name],
	[BTDiseaseType].[BTTherapeuticAreaId] [BTTherapeuticAreaId],
	[BTTherapeuticArea].[Name] [BTTherapeuticArea.Name]
FROM
	[dbo].[BTDiseaseType] [BTDiseaseType] WITH(NOLOCK)
	LEFT OUTER JOIN [dbo].[BTTherapeuticarea] [BTTherapeuticArea] WITH(NOLOCK) ON ([BTTherapeuticArea].[Id] = [BTDiseaseType].[BTTherapeuticAreaId])
WHERE
	(EXISTS (
SELECT
	[SubBTProjectDisease].[Id] [Id]
FROM
	[dbo].[BTProjectDisease] [SubBTProjectDisease] WITH(NOLOCK)
WHERE
	[SubBTProjectDisease].[BTDiseaseTypeId] = [BTDiseaseType].[Id]
	AND [SubBTProjectDisease].[EWBProjectId] = @EWBProjectId)
AND NOT EXISTS (
SELECT
	[SubSpecificationByDiseaseType].[Id] [Id]
FROM
	[dbo].[SpecificationByDiseaseType] [SubSpecificationByDiseaseType] WITH(NOLOCK)
WHERE
	[SubSpecificationByDiseaseType].[DiseaseTypeId] = [BTDiseaseType].[Id]
	AND [SubSpecificationByDiseaseType].[ProjectSpecificationId] = @ProjectSpecificationId))
ORDER BY
	[BTTherapeuticArea.Name] DESC

 

Добрый день.

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

Ниже привожу пример подобной фильтрации:

if (project &amp;&amp; project.value) {
	var filterGroup = this.Terrasoft.createFilterGroup();
	var subFilters = Terrasoft.createFilterGroup();
    subFilters.addItem(Terrasoft.createColumnFilterWithParameter(
		Terrasoft.ComparisonType.EQUAL, "EWBProject", project.value));
	filterGroup.addItem(this.Terrasoft.createExistsFilter("[BTProjectDisease:BTDiseaseType:Id].Id",
		subFilters));
	var subFilters1 = Terrasoft.createFilterGroup();
	subFilters1.addItem(Terrasoft.createColumnFilterWithParameter(
		Terrasoft.ComparisonType.EQUAL, "ProjectSpecification", this.get("MasterRecordId")));
	filterGroup.addItem(this.Terrasoft.createNotExistsFilter(" 
       [SpecificationByDiseaseType:DiseaseType:Id].Id",	subFilters1));
}

В результате в базу данных сформируется такой SQL-запрос:

SELECT
	[BTDiseaseType].[Id] [Id],
	[BTDiseaseType].[Name] [Name],
	[BTDiseaseType].[BTTherapeuticAreaId] [BTTherapeuticAreaId],
	[BTTherapeuticArea].[Name] [BTTherapeuticArea.Name]
FROM
	[dbo].[BTDiseaseType] [BTDiseaseType] WITH(NOLOCK)
	LEFT OUTER JOIN [dbo].[BTTherapeuticarea] [BTTherapeuticArea] WITH(NOLOCK) ON ([BTTherapeuticArea].[Id] = [BTDiseaseType].[BTTherapeuticAreaId])
WHERE
	(EXISTS (
SELECT
	[SubBTProjectDisease].[Id] [Id]
FROM
	[dbo].[BTProjectDisease] [SubBTProjectDisease] WITH(NOLOCK)
WHERE
	[SubBTProjectDisease].[BTDiseaseTypeId] = [BTDiseaseType].[Id]
	AND [SubBTProjectDisease].[EWBProjectId] = @EWBProjectId)
AND NOT EXISTS (
SELECT
	[SubSpecificationByDiseaseType].[Id] [Id]
FROM
	[dbo].[SpecificationByDiseaseType] [SubSpecificationByDiseaseType] WITH(NOLOCK)
WHERE
	[SubSpecificationByDiseaseType].[DiseaseTypeId] = [BTDiseaseType].[Id]
	AND [SubSpecificationByDiseaseType].[ProjectSpecificationId] = @ProjectSpecificationId))
ORDER BY
	[BTTherapeuticArea.Name] DESC

 

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

Добрый день!

Подскажите, какими оптимально способами решать задачу, чтобы определенные пользователи видели и могли редактировать только Контрагентов с типом Клиент?

Спасибо!

Нравится

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

Здравствуйте! Через БП, воспользовавшись элементом раздать права. Создаёте БП со стартовым сигналом по объекту после добавления записи и раздаёт нужные права, это для новых пользователей, а для существующих через БП с простым стартом, используйте тот же элемент раздать права доступа и задаёте в нем объект о фильтры.

Здравствуйте! Через БП, воспользовавшись элементом раздать права. Создаёте БП со стартовым сигналом по объекту после добавления записи и раздаёт нужные права, это для новых пользователей, а для существующих через БП с простым стартом, используйте тот же элемент раздать права доступа и задаёте в нем объект о фильтры.

Нигрескул Алексей,

 

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

Потом еще как вариант - плокировка страницы

 

https://academy.terrasoft.ru/documents/technic-sdk/7-16/kak-polnostyu-z…

https://academy.terrasoft.ua/documents/technic-sdk/7-16/mehanizm-blokir…

 

Использую и вариант с БП и с блокировкой страницы, но если нужна более гарантирования возможность блокировки то второй вариант

Александр Тыра,

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

Александр Тыра пишет:

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

Насколько понимаю, нет, не перетрут. Пишут:

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

 А если Вы пробовали и именно затирает, пожалуйста, напишите в поддержку подробности, как воспроизвели.

 

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

Александр Тыра пишет:

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

Мы просто запрещаем пользователям менять права вручную. И автоматизируем распределение прав полностью. 

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

Добрый день,

 

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

Переопределяя метод initCardPrintForms и в нем добавляя условия для выборки, в режиме отображения карточки все работает как надо.

​
var printFormsMenuCollection = resultCollection.filterByFn(function(item) {
    return item.get("ShowInCard") === true &&(this.getFilterForReportsOrBooleanValue(item));
}, this);
 
​
getFilterForReportsOrBooleanValue(item) {
		var value = this.get("NrbPurchaseMethod");
				switch(value.displayValue) {
					case "Аукцион":
							return	item.get("Caption") === "Извещение Аукцион" || 
									item.get("Caption") === "Документация Аукцион";
				default:
							return false;
		}
},

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

Как правильно реализовать фильтрацию?

Нравится

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

Павел, а в чём проблема, если в обоих случаях будет запускаться одна и та же функция с доработками?

И initCardPrintForms, и initSectionPrintForms применяются в BaseDataView, базовой странице раздела:

/**
 * Initializes print buttons menu.
 * @protected
 * @param {Function} callback Callback function.
 * @param {Object} scope Callback function scope.
 */
initPrintButtonsMenu: function(callback, scope) {
	this.initSectionPrintForms(this.initCardPrintForms, this);
	this.initModulePrintForms(callback, scope);
},

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

{
	"operation": "insert",
	"name": "SeparateModeReportsButton",
	"parentName": "SeparateModeActionButtonsRightContainer",
	"propertyName": "items",
	"values": {
		"itemType": Terrasoft.ViewItemType.BUTTON,
		"caption": {"bindTo": "Resources.Strings.PrintButtonCaption"},
		"classes": {"wrapperClass": ["actions-button-margin-right"]},
		"controlConfig": {
			"menu": {"items": {"bindTo": "SectionPrintMenuItems"}},
			"visible": {"bindTo": "IsSectionPrintButtonVisible"}
		}
	}
},
...
{
	"operation": "insert",
	"name": "CombinedModePrintButton",
	"parentName": "CombinedModeActionButtonsCardRightContainer",
	"propertyName": "items",
	"values": {
		"itemType": Terrasoft.ViewItemType.BUTTON,
		"caption": {"bindTo": "Resources.Strings.PrintButtonCaption"},
		"classes": {"wrapperClass": ["actions-button-margin-right"]},
		"controlConfig": {"menu": {"items": {"bindTo": "CardPrintMenuItems"}}},
		"visible": {"bindTo": "IsCardPrintButtonVisible"}
	}
},

 

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

Добрый день, уважаемые коллеги!

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

Рассматриваю применение 2-х вариантов:

Бизнес-правило 1: Фильтр записей Подразделений по признаку UsrProhibitSelectionAccount (см. ниже 1-й метод). Метод отрабатывает и при выборе отображает только то, что можно

Бизнес-правило 2: Выдавать сообщение пользователю, если выбранная ранее запись некорректна (см. ниже 2-й метод).  И вот тут почему-то в консоли видно, что не считывается корректно значение поля UsrProhibitSelectionAccount. Оно всегда false. Правда не во всех записях оно заполнено (см. скрин).

Помогите, пожалуйста, определить в чем некорректность 2-го метода. Благодарю за помощь

// Правило 1
/*Terrasoft.sdk.Model.addBusinessRule("Account", {
	ruleType: Terrasoft.RuleTypes.Filtration,
	position: 1,
	triggeredByColumns: ["UsrDepartment"],
	events: [Terrasoft.BusinessRuleEvents.ValueChanged,Terrasoft.BusinessRuleEvents.Load],
	 message: Terrasoft.LocalizableStrings.DepartmentMustBeAllowed,
	 filters: Ext.create("Terrasoft.Filter", {
        modelName: "UsrAccountDepartments",
        property: "UsrProhibitSelectionAccount",
        value: false
    })
});*/
 
// Правило 2
Terrasoft.sdk.Model.addBusinessRule("Account", {
	name: "AccountDepartmentMustBeAllowedRule",
	ruleType: Terrasoft.RuleTypes.Custom,
	triggeredByColumns: ["UsrDepartment"],
	events: [Terrasoft.BusinessRuleEvents.Load,
		Terrasoft.BusinessRuleEvents.ValueChanged, Terrasoft.BusinessRuleEvents.Save],
	executeFn: function(record, rule, column, customData, callbackConfig) {
		var AccountDepartment = record.get("UsrDepartment");
	var isValid = AccountDepartment.get("UsrProhibitSelectionAccount");
 
		record.changeProperty("UsrDepartment", {
			isValid: {
				value: isValid,
				message: Terrasoft.LocalizableStrings.DepartmentMustBeAllowed
			}
		});
		Ext.callback(callbackConfig.success, callbackConfig.scope, [isValid]);
	}
});

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

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

Нравится

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

Марина, а оно точно так должно синхронно читать из объекта справочника так, как у Вас?

В схеме MobileActivityOpportunityModelConfig значение Opportunity.Account читают с асинхронным вызовом так:

Terrasoft.sdk.Model.addBusinessRule("Activity", {
	name: "ActivityAccountOpportunityFiltrationRule",
	ruleType: Terrasoft.RuleTypes.Filtration,
	events: [Terrasoft.BusinessRuleEvents.Load, Terrasoft.BusinessRuleEvents.ValueChanged],
	triggeredByColumns: ["Account"],
	filteredColumn: "Opportunity",
	filters: Ext.create("Terrasoft.Filter", {
		property: "Account"
	})
});
 
Terrasoft.sdk.Model.addBusinessRule("Activity", {
	name: "ActivityAccountByOpportunityRule",
	ruleType: Terrasoft.RuleTypes.Custom,
	triggeredByColumns: ["Opportunity"],
	events: [Terrasoft.BusinessRuleEvents.ValueChanged, Terrasoft.BusinessRuleEvents.Save,
		Terrasoft.BusinessRuleEvents.Load],
	executeFn: function(record, rule, column, customData, callbackConfig) {
		var opportunityRecord = record.get("Opportunity");
		if (opportunityRecord) {
			var accountRecord = record.get("Account");
			if (!accountRecord) {
				var opportunityModel = Ext.ModelManager.getModel("Opportunity");
				opportunityModel.load(opportunityRecord.getId(), {
					isCancelable: false,
					queryConfig: Ext.create("Terrasoft.QueryConfig", {
						columns: ["Account"],
						modelName: "Opportunity"
					}),
					success: function(loadedRecord) {
						if (loadedRecord) {
							record.set("Account", loadedRecord.get("Account"), true);
						}
						Ext.callback(callbackConfig.success, callbackConfig.scope);
					},
					failure: function(record, operation) {
						var exception = operation.getError();
						Ext.callback(callbackConfig.failure, callbackConfig.scope, [exception]);
					},
					scope: this
				});
				return;
			}
		}
		Ext.callback(callbackConfig.success, callbackConfig.scope);
	},
	position: 1
});

Также на скриншоте видно, что колонка UsrProhibitSelectionAccount  в локальной БД пустая. Из-за этого логика может отрабатывать некорректно. Нужно правильно настроить фильтрацию синхронизации в манифесте и пересинхронизировать с нуля. 

Марина, а оно точно так должно синхронно читать из объекта справочника так, как у Вас?

В схеме MobileActivityOpportunityModelConfig значение Opportunity.Account читают с асинхронным вызовом так:

Terrasoft.sdk.Model.addBusinessRule("Activity", {
	name: "ActivityAccountOpportunityFiltrationRule",
	ruleType: Terrasoft.RuleTypes.Filtration,
	events: [Terrasoft.BusinessRuleEvents.Load, Terrasoft.BusinessRuleEvents.ValueChanged],
	triggeredByColumns: ["Account"],
	filteredColumn: "Opportunity",
	filters: Ext.create("Terrasoft.Filter", {
		property: "Account"
	})
});
 
Terrasoft.sdk.Model.addBusinessRule("Activity", {
	name: "ActivityAccountByOpportunityRule",
	ruleType: Terrasoft.RuleTypes.Custom,
	triggeredByColumns: ["Opportunity"],
	events: [Terrasoft.BusinessRuleEvents.ValueChanged, Terrasoft.BusinessRuleEvents.Save,
		Terrasoft.BusinessRuleEvents.Load],
	executeFn: function(record, rule, column, customData, callbackConfig) {
		var opportunityRecord = record.get("Opportunity");
		if (opportunityRecord) {
			var accountRecord = record.get("Account");
			if (!accountRecord) {
				var opportunityModel = Ext.ModelManager.getModel("Opportunity");
				opportunityModel.load(opportunityRecord.getId(), {
					isCancelable: false,
					queryConfig: Ext.create("Terrasoft.QueryConfig", {
						columns: ["Account"],
						modelName: "Opportunity"
					}),
					success: function(loadedRecord) {
						if (loadedRecord) {
							record.set("Account", loadedRecord.get("Account"), true);
						}
						Ext.callback(callbackConfig.success, callbackConfig.scope);
					},
					failure: function(record, operation) {
						var exception = operation.getError();
						Ext.callback(callbackConfig.failure, callbackConfig.scope, [exception]);
					},
					scope: this
				});
				return;
			}
		}
		Ext.callback(callbackConfig.success, callbackConfig.scope);
	},
	position: 1
});

Также на скриншоте видно, что колонка UsrProhibitSelectionAccount  в локальной БД пустая. Из-за этого логика может отрабатывать некорректно. Нужно правильно настроить фильтрацию синхронизации в манифесте и пересинхронизировать с нуля. 

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

 

Александр, большое спасибо за рекомендации. Да, видимо, я неверно читаю объект справочника. Надо попробовать разобраться с асинхронным вызовом. Спасибо за приведенный пример.

Заполнение колонки UsrProhibitSelectionAccount в локальной базе пока не помогло.

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