Добрый день, подскажите можно ли создавать в разделах подразделы? Примерно по такой схеме?:

!

Нравится

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

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

Отличное решение для Вашей бизнес-задачи это добавление деталей на страницу - https://academy.terrasoft.ru/documents/sales-enterprise/7-9/master-deta…
В результате получиться аналогичная картина.

Наглядные примеры:

- раздел «Контрагенты» – деталь «Контакты контрагента»;
- раздел «Счет» – деталь «Продукты»;
- раздел «Контакты» - деталь «Адреса».

Скорее, это все решается группами, так как разделение по странам - это лишь один из вариантов разделения заказов

Большое спасибо :smile:
Подскажите, пожалуйста, как можно добавить автоподстановку значения поля из другого раздела? К примеру, в новом разделе есть поля-справочники: продукт и страна, необходимо, чтобы при выборе продукта в поле страна из раздела Продукты соответствующему продукту сразу подставлялась страна, ранее указанная в разделе Продукты.

"Maria H" написал:чтобы при выборе продукта в поле страна из раздела Продукты соответствующему продукту сразу подставлялась страна, ранее указанная в разделе Продукты.

Так бизнес правило фильтрации с включенным "autocomplete": true, же:

https://academy.terrasoft.ru/documents/technic-sdk/7-9/primer-primeneni…

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

Необходимо, чтобы в зависимости от выбранного продукта подставлялся регион, оба поля являются справочниками.
Screenshot
Сам же регион выставлен каждому продукту в таблице "Продукты".

rules: {
                "UsrRegion": {
                    "FiltrationRegionByProduct": {
                        "ruleType": BusinessRuleModule.enums.RuleType.FILTRATION,
                        "autocomplete": true,
                        "autoClean": true,
                        "baseAttributePatch": "Product",
                        "comparisonType": Terrasoft.ComparisonType.EQUAL,
                        "type": BusinessRuleModule.enums.ValueType.ATTRIBUTE,
                        "attribute": "UsrRegion"
                    }
                },

"Maria H" написал:Необходимо, чтобы в зависимости от выбранного продукта подставлялся регион, оба поля являются справочниками.

Попробуйте так:

rules: {
"Product": {
"FiltrationRegionByProduct": {
"ruleType": BusinessRuleModule.enums.RuleType.FILTRATION,
"autocomplete": true,
"autoClean": true,
"baseAttributePatch": "UsrRegion",
"comparisonType": Terrasoft.ComparisonType.EQUAL,
"type": BusinessRuleModule.enums.ValueType.ATTRIBUTE,
"attribute": "UsrRegion"
}
},

спасибо, не помогло :sad:, может необходимо как-то конкретно в коде указать что фильтрация идет по полю UsrRegion из раздела продукты, в зависимости от выбранного продукта в данном разделе, как это можно сделать?

"Maria H" написал:спасибо, не помогло , может необходимо как-то конкретно в коде указать что фильтрация идет по полю UsrRegion из раздела продукты, в зависимости от выбранного продукта в данном разделе, как это можно сделать?

Нужно очень точно указать имена колонок, так как они указаны в объектах.
Проще будет написать вам в поддержку support@terrasoft.ru с указанием доступа к сайту, сотрудники поддержки уже все на месте поправят, а то предугадывать возможные названия колонок на форуме сложно.

Большое спасибо! :smile: Перепроверили еще раз наименования полей и с вашим вариантом сработало.

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

Добрый день!

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

Буду очень признателен Вашей помощи.

Нравится

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

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

Если через DCM, то нужно создать подпроцесс.

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

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

[quote="Демьяник Алексей"]
Благодарю за ответ.

"Демьяник Алексей" написал:

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

Алексей, добрый день!

У меня похожий вопрос. Из карточки контакта перехожу в пользовательскую активность и не получается унаследовать ФИО и пр. из карточки контакта.

Процесс запускаю по сигнальному элементу, в котором отслеживаю добавление записи с конкретными типом активности. Далее, по ID читаю Активность и читаю Контакт. Затем записываю ФИО из Контакта в нужное поле активности. И,... ничего не записывается. Прошу подсказать, что нужно изменить?
Заранее благодарен!

Сергей, здравствуйте!

Алгоритм решения:
А. Создать процесс, условно CreateActivity:
1. Добавить в процесс параметр с типом Уникальный идентификатор – условно ParamContactId.
2. Добавить данные в объект Активность. Заполнить интересующие поля, указать [Тип = Выставка], [Контакт – ФИО = ParamContactId].
3. Элемент [Открыть страницу редактирования], открыть страницу существующей активности, где Id = Пункт 2.Id созданной записи.

Б. Заместить страницу редактирования контакта:
1. Добавить пользовательское действие.
2. Добавить обработчик. Обработчик будет:
- запускать процесс CreateActivity
- в параметр процесса ParamContactId – передавать Id текущего контакта

Пример создания пользовательской кнопки/действия и обработчика (запуск процесса) есть на академии и community:
https://academy.terrasoft.ua/documents/technic-sdk/7-9/zapusk-processa-…
http://www.community.terrasoft.ru/forum/topic/10554
http://www.community.terrasoft.ru/forum/topic/14042

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

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

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

Вот код из академии:

define("OrderPageV2", [], function() {
return {
// Название схемы объекта страницы редактирования.
entitySchemaName: "Order",
details: /**SCHEMA_DETAILS*/{}/**SCHEMA_DETAILS*/,
// Свойство attributes модели представления.
attributes: {
// Название атрибута модели представления.
"UsrBalance": {
// Тип данных колонки модели представления.
dataValueType: Terrasoft.DataValueType.FLOAT,
// Массив конфигурационных объектов, определяющих зависимости колонки [UsrBalance].
dependencies: [
{
// Значение колонки [UsrBalance] зависит от значений колонок [Amount]
// и [PaymentAmount].
columns: ["Amount", "PaymentAmount"],
// Метод-обработчик, который вызывается при изменении значения одной из колонок [Amount]
// и [PaymentAmount].
methodName: "calculateBalance"
}
]
}
},
// Коллекция методов модели представления страницы редактирования.
methods: {
// Переопределение базового метода Terrasoft.BasePageV2.onEntityInitialized, который
// срабатывает после окончания инициализации схемы объекта страницы редактирования.
onEntityInitialized: function() {
// Вызывается родительская реализация метода.
this.callParent(arguments);
// Вызов метода-обработчика, который рассчитывает значение колонки [UsrBalance].
this.calculateBalance();
},
// Метод-обработчик, который рассчитывает значение колонки [UsrBalance].
calculateBalance: function() {
// Проверка, проинициализованы ли в момент открытия страницы редактирования
// колонки [Amount] и [PaymentAmount]. Если нет, то для них устанавливаются нулевые значения.
if (!this.get("Amount")) {
this.set("Amount", 0);
}
if (!this.get("PaymentAmount")) {
this.set("PaymentAmount", 0);
}
// Расчет разницы между значениями в колонках [Amount] и [PaymentAmount].
var result = this.get("Amount") - this.get("PaymentAmount");
// Результат расчета присваивается в качестве значения колонке [UsrBalance].
this.set("UsrBalance", result);
}
},
// Визуальное отображение поля [Остаток для оплаты] на странице редактирования.
diff: /**SCHEMA_DIFF*/[
{
"operation": "insert",
"parentName": "Header",
"propertyName": "items",
"name": "UsrBalance",
"values": {
"bindTo": "UsrBalance",
"layout": {"column": 12, "row": 2, "colSpan": 12}
}
}
]/**SCHEMA_DIFF*/
};
});

Нравится

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

Добрый день.

Для того что бы менять поле Состояние оплаты, Вам необходимо добавить свою логику в метод calculateBalance. На основании добавленной логики необходимо менять значение атрибута PaymentStatus.
Поскольку данный атрибут содержит справочное значение, передавать ему необходимо объект следующего вида: {value: "Id записи", displayValue: "Отображаемое значение"}.

Пример:

this.set("PaymentStatus", {value: "448d1338-d3a5-4fd4-9a6e-769403f89896", displayValue: "Оплачен полностью"});
this.set("PaymentStatus", {value: "309e5219-114d-4a6e-b5b0-fe33caeca4dd", displayValue: "Отменен"});

Спасибо, попробую.
П.С. Перед этим ID надо узнать, этот указан как пример, вообще там же будет параметр, который перед этим достану?

id статусов, Вы можете получить из таблицы OrderPaymentStatus или же посмотреть в справочнике.
Получить текущее значение статуса возможно следующим кодом:

var statusId = this.get("PaymentStatus").value

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

Добрый день!

Коллеги, подскажите, пожалуйста, какой наиболее корректный способ массово (в цикле) удалять записи в БД с помощью ESQ?

Вариант с foreach:

EntitySchema schemaDeleteEntity =userConnection.EntitySchemaManager.GetInstanceByName(EntityName);
EntitySchemaQuery esqDeleteEntity = new EntitySchemaQuery(schemaDeleteEntity);
esqDeleteEntity.AddAllSchemaColumns();
esqDeleteEntity.Filters.Add(esqDeleteEntity.CreateFilterWithParameters(FilterComparisonType.Equal, AccountIdField, AccountId));
EntityCollection entitiesDeleteEntity = esqDeleteEntity.GetEntityCollection(userConnection);
  foreach (Entity deleteentity in  entitiesDeleteEntity)
  {
      deleteentity.Delete();
  }

возвращает exception "Коллекция была изменена после создания экземпляра перечислителя."

Если заменить на простой for:

for(int i = entitiesDeleteEntity.Count-1;i>=0;i--)
{
        entitiesDeleteEntity[i].Delete();
}

Код отрабатывает корректно, но при нагрузке удаление периодически вызывает exception о незавршённых транзакциях вида:
Данный SqlTransaction завершен; его повторное использование невозможно.   в System.Data.SqlClient.SqlTransaction.ZombieCheck()
   в System.Data.SqlClient.SqlTransaction.Rollback()
   в Terrasoft.Core.DB.DBExecutor.RollbackTransaction()
   в Terrasoft.Core.Entities.Entity.ExecuteDelete(Delete delete, Object keyValue)
   в Terrasoft.Core.Entities.Entity.Delete(Object keyValue)
   в Terrasoft.Core.Entities.Entity.Delete()

Как всё-таки правильнее?

Спасибо!

Нравится

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

Добрый день!
Для массового удаления лучше не использовать EntitySchemaQuery, так как ESQ накладывает права на запрос. Лучше всего использовать либо класс Delete, или же использовать хранимую процедуру.
Единственный случай, когда нужно использовать ESQ - это если вам нужно запускать процессы, которые настроенны на сигнал "удаления записи", но и в этом случае лучше найти альтернативу по запуску доп логики после удаления

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

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

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

define("AccountSectionV2", ["ProcessModuleUtilities"], function(ProcessModuleUtilities)

Сделал так, теперь не загружается даже страница контрагента. (Кэш чистил и компилировал все)

Вот код:

define("AccountSectionV2", [ProcessModuleUtilities], function(ProcessModuleUtilities) {
return {
// Название схемы объекта страницы редактирования.
entitySchemaName: "Account",
methods: {
runProcess: function() {
var activeRowId = this.get("Id");
var args = {
sysProcessName: "UsrMyProcess",
parameters: {
OppID: activeRowId
}
};
ProcessModuleUtilities.executeProcess(args.sysProcessName, args.parameters, this);
}
},
//Настройка визуализации кнопки на странице редактирования.
diff: [
// Метаданные для добавления на страницу пользовательской кнопки.
{
// Указывает на то, что выполняется операция добавления элемента на страницу.
"operation": "insert",
// Мета-имя родительского элемента управления, в который добавляется кнопка.
"parentName": "CombinedModeActionButtonsCardLeftContainer",
// Указывает на то, что кнопка добавляется в коллекцию элементов управления
// родительского элемента (мета-имя которого указано в parentName).
"propertyName": "items",
// Мета-имя добавляемой кнопки.
"name": "runProcessButton",
// Дополнительные свойства элемента.
"values": {
// Тип добавляемого элемента — кнопка.
"itemType": Terrasoft.ViewItemType.BUTTON,
// Привязка заголовка кнопки к локализуемой строке схемы.
"caption": "Запустить БП",
// Привязка метода-обработчика нажатия кнопки.
"click": {bindTo: "runProcess"},
// Стиль отображения кнопки.
"style": Terrasoft.controls.ButtonEnums.style.GREEN,
"enabled": true
}
}
]
};
});

Нравится

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

"Калушка Д." написал:define("AccountSectionV2", [ProcessModuleUtilities], function(ProcessModuleUtilities)

Во-первых: ProcessModuleUtilities должен быть в кавычках в []
Во-вторых: executeProcess принимает лишь 1 аргумент

executeProcess: function(args) {...}

либо можно использовать метод runProcess из того же ProcessModuleUtilities

runProcess: function(processName, processParameters, callback, scope) {...}

Ну и Id активной записи берется через this.get("ActiveRow")

Данила, большое спасибо!

Кому интересно, вот рабочий код :

define("AccountSectionV2", ["ProcessModuleUtilities"], function(ProcessModuleUtilities) {
return {
// Название схемы объекта страницы редактирования.
entitySchemaName: "Account",
methods: {
runProcess: function() {
var activeRowId = this.get("ActiveRow");
var args = {
sysProcessName: "UsrMyProcess",
parameters: {
OppID: activeRowId
}
};
ProcessModuleUtilities.executeProcess(args);
}
},
//Настройка визуализации кнопки на странице редактирования.
diff: [
// Метаданные для добавления на страницу пользовательской кнопки.
{
// Указывает на то, что выполняется операция добавления элемента на страницу.
"operation": "insert",
// Мета-имя родительского элемента управления, в который добавляется кнопка.
"parentName": "CombinedModeActionButtonsCardLeftContainer",
// Указывает на то, что кнопка добавляется в коллекцию элементов управления
// родительского элемента (мета-имя которого указано в parentName).
"propertyName": "items",
// Мета-имя добавляемой кнопки.
"name": "runProcessButton",
// Дополнительные свойства элемента.
"values": {
// Тип добавляемого элемента — кнопка.
"itemType": Terrasoft.ViewItemType.BUTTON,
// Привязка заголовка кнопки к локализуемой строке схемы.
"caption": "Запустить БП",
// Привязка метода-обработчика нажатия кнопки.
"click": {bindTo: "runProcess"},
// Стиль отображения кнопки.
"style": Terrasoft.controls.ButtonEnums.style.GREEN,
"enabled": true
}
}
]
};
});

Еще момент.
Решил добавить в карточку контрагента еще кнопку, чтобы не только в совместном режиме она отображалась, но что-то она никак не появляется - Кнопка. Может контейнер не тот...

define("AccountPageV2", ["ProcessModuleUtilities"], function(ProcessModuleUtilities) {
return {
// Название схемы объекта страницы редактирования.
entitySchemaName: "Account",
methods: {
runProcess: function() {
var activeRowId = this.get("ActiveRow");
var args = {
sysProcessName: "UsrMyProcess",
parameters: {
OppID: activeRowId
}
};
ProcessModuleUtilities.executeProcess(args);
}
},
//Настройка визуализации кнопки на странице редактирования.
diff: [
// Метаданные для добавления на страницу пользовательской кнопки.
{
// Указывает на то, что выполняется операция добавления элемента на страницу.
"operation": "insert",
// Мета-имя родительского элемента управления, в который добавляется кнопка.
"parentName": "LeftContainer",
// Указывает на то, что кнопка добавляется в коллекцию элементов управления
// родительского элемента (мета-имя которого указано в parentName).
"propertyName": "items",
// Мета-имя добавляемой кнопки.
// родительского элемента (мета-имя которого указано в parentName).
"name": "runProcessButton",
// Дополнительные свойства элемента.
"values": {
// Тип добавляемого элемента — кнопка.
"itemType": Terrasoft.ViewItemType.BUTTON,
// Привязка заголовка кнопки к локализуемой строке схемы.
"caption": "Запустить БП",
// Привязка метода-обработчика нажатия кнопки.
"click": {bindTo: "runProcess"},
// Стиль отображения кнопки.
"style": Terrasoft.controls.ButtonEnums.style.GREEN
}
}
]
};
});

Еще момент.
Решил добавить в карточку контрагента еще кнопку, чтобы не только в совместном режиме она отображалась, но что-то она никак не появляется - Кнопка. Может контейнер не тот...

define("AccountPageV2", ["ProcessModuleUtilities"], function(ProcessModuleUtilities) {
return {
// Название схемы объекта страницы редактирования.
entitySchemaName: "Account",
methods: {
runProcess: function() {
var activeRowId = this.get("ActiveRow");
var args = {
sysProcessName: "UsrMyProcess",
parameters: {
OppID: activeRowId
}
};
ProcessModuleUtilities.executeProcess(args);
}
},
//Настройка визуализации кнопки на странице редактирования.
diff: [
// Метаданные для добавления на страницу пользовательской кнопки.
{
// Указывает на то, что выполняется операция добавления элемента на страницу.
"operation": "insert",
// Мета-имя родительского элемента управления, в который добавляется кнопка.
"parentName": "LeftContainer",
// Указывает на то, что кнопка добавляется в коллекцию элементов управления
// родительского элемента (мета-имя которого указано в parentName).
"propertyName": "items",
// Мета-имя добавляемой кнопки.
// родительского элемента (мета-имя которого указано в parentName).
"name": "runProcessButton",
// Дополнительные свойства элемента.
"values": {
// Тип добавляемого элемента — кнопка.
"itemType": Terrasoft.ViewItemType.BUTTON,
// Привязка заголовка кнопки к локализуемой строке схемы.
"caption": "Запустить БП",
// Привязка метода-обработчика нажатия кнопки.
"click": {bindTo: "runProcess"},
// Стиль отображения кнопки.
"style": Terrasoft.controls.ButtonEnums.style.GREEN
}
}
]
};
});

"Калушка Д." написал:но что-то она никак не появляется

Все вроде как правильно. Проверьте в адресной строке, находитесь ли вы в AccountPage.
+ На схеме редактирования страницы Id берется через this.get("Id");

И ради все богов, используйте для кода теги (кнопочка js)

//Вот так вот

"Варфоломеев Данила" написал:И ради все богов, используйте для кода теги (кнопочка js)

Так, вроде, стоят практически повсюду )
В AccountSectionV2 кнопка есть, а тут AccountPageV2 не появляется

define("AccountPageV2", ["ProcessModuleUtilities"], function(ProcessModuleUtilities) {
return {
// Название схемы объекта страницы редактирования.
entitySchemaName: "Account",

diff: [
// Метаданные для добавления на страницу пользовательской кнопки.
{
// Указывает на то, что выполняется операция добавления элемента на страницу.
"operation": "insert",
// Мета-имя родительского элемента управления, в который добавляется кнопка.
"parentName": "LeftContainer",
// Указывает на то, что кнопка добавляется в коллекцию элементов управления
// родительского элемента (мета-имя которого указано в parentName).
"propertyName": "items",
// Мета-имя добавляемой кнопки.
// родительского элемента (мета-имя которого указано в parentName).
"name": "runProcessButton",
// Дополнительные свойства элемента.
"values": {
// Тип добавляемого элемента — кнопка.
"itemType": Terrasoft.ViewItemType.BUTTON,
// Привязка заголовка кнопки к локализуемой строке схемы.
"caption": {bindTo: "Resources.Strings.runProcessButtonCaption"},
// Привязка метода-обработчика нажатия кнопки.
"click": {bindTo: "runProcess"},
"visible": true,
"enabled": true,
// Стиль отображения кнопки.
"style": Terrasoft.controls.ButtonEnums.style.GREEN,
"layout": {
"column": 1,
"row": 6,
"colSpan": 1
}
}
}
]
};
});

"Калушка Д." написал:AccountPageV2 не появляется

триждыдолбаный layout во всем виноват.... если его не указать даже debugger в onEntityInitialized не отрабатывает. 11/8 would add button again, как говорится.

{
	"operation": "insert",
	"parentName": "LeftContainer",
	"propertyName": "items",
	"name": "customBtn",
	"values": {
		"itemType": Terrasoft.ViewItemType.BUTTON,
		"caption": "RunProcess",
		"click": {"bindTo": "runProcess"},
		"visible": true,
		"layout": {
            "column": 1,
            "row": 7,
            "colSpan": 1
        }
	}
}

Сорян, но нет *(
По прежнему не видно.

Вот эта демка -https://005176-crm-bundle.bpmonline.com
Supervisor
Если будет желание узнать в чем причина. Только надо открывать не из раздела (там все ок), а по ссылке, например из контакта.

"Калушка Д." написал:По прежнему не видно.

Сегодня с утра еще раз перепроверил, вот такой код сработал локально на последней демке:

define("AccountPageV2", ["ProcessModuleUtilities"], function(ProcessModuleUtilities) {
	return {
	// Название схемы объекта страницы редактирования.
	entitySchemaName: "Account",
	methods: {
		runProcess: function() {
			alert("Работай, чертова кнопка >:-(");
		}
	},
	//Настройка визуализации кнопки на странице редактирования.
	diff: [
		{
			"operation": "insert",
			"parentName": "LeftContainer",
			"propertyName": "items",
			"name": "customProcessButton",
			"values": {
				"itemType": Terrasoft.ViewItemType.BUTTON,
				"caption": "RunProcess",
				"click": {"bindTo": "runProcess"},
				"visible": true,
				"style": "red"
			}
		},
		{
			"operation": "insert",
			"parentName": "LeftContainer",
			"propertyName": "items",
			"name": "customProcessButtonSecondary",
			"values": {
				"itemType": Terrasoft.ViewItemType.BUTTON,
				"caption": "KNOPKA #2",
				"click": {"bindTo": "runProcess"},
				"visible": true,
				"style": "blue"
			}
		}
	]};
});

Самое странное, что вчера абсолютно такой же код не отрабатывал ни в какую. У вас на системе протестить не могу - все дико лагает + система не может даже страницу сохранить, конфигурация валится с ошибкой)

Ребята, большое спасибо за помощь!!!

В итоге, вот рабочий код :

define("AccountPageV2", ["ProcessModuleUtilities"], function(ProcessModuleUtilities) {
return {
entitySchemaName: "Account",
details: /**SCHEMA_DETAILS*/{}/**SCHEMA_DETAILS*/,
diff: /**SCHEMA_DIFF*/[
{
// Указывает на то, что выполняется операция добавления элемента на страницу.
"operation": "insert",
// Мета-имя родительского элемента управления, в который добавляется кнопка.
"parentName": "LeftContainer",
// Указывает на то, что кнопка добавляется в коллекцию элементов управления
// родительского элемента (мета-имя которого указано в parentName).
"propertyName": "items",
// Мета-имя добавляемой кнопки.
// родительского элемента (мета-имя которого указано в parentName).
"name": "runProcessButton",
// Дополнительные свойства элемента.
"values": {
// Тип добавляемого элемента — кнопка.
"itemType": Terrasoft.ViewItemType.BUTTON,
// Привязка заголовка кнопки к локализуемой строке схемы.
"caption": "Запустить БП",
// Привязка метода-обработчика нажатия кнопки.
"click": {bindTo: "runProcess"},
// Стиль отображения кнопки.
"style": Terrasoft.controls.ButtonEnums.style.GREEN
}
}
]/**SCHEMA_DIFF*/,
methods: {
runProcess: function() {
var activeRowId = this.get("Id");
var args = {
sysProcessName: "UsrMyProcess",
parameters: {
OppID: activeRowId
}
};
ProcessModuleUtilities.executeProcess(args);
}
},
rules: {}
};
});

Калушка Д. пишет:

Ребята, большое спасибо за помощь!!!

В итоге, вот рабочий код :

define("AccountPageV2", ["ProcessModuleUtilities"], function(ProcessModuleUtilities) {

return {

entitySchemaName: "Account",

details: /**SCHEMA_DETAILS*/{}/**SCHEMA_DETAILS*/,

diff: /**SCHEMA_DIFF*/[

{

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

"operation": "insert",

// Мета-имя родительского элемента управления, в который добавляется кнопка.

"parentName": "LeftContainer",

// Указывает на то, что кнопка добавляется в коллекцию элементов управления

// родительского элемента (мета-имя которого указано в parentName).

"propertyName": "items",

// Мета-имя добавляемой кнопки.

// родительского элемента (мета-имя которого указано в parentName).

"name": "runProcessButton",

// Дополнительные свойства элемента.

"values": {

// Тип добавляемого элемента — кнопка.

"itemType": Terrasoft.ViewItemType.BUTTON,

// Привязка заголовка кнопки к локализуемой строке схемы.

"caption": "Запустить БП",

// Привязка метода-обработчика нажатия кнопки.

"click": {bindTo: "runProcess"},

// Стиль отображения кнопки.

"style": Terrasoft.controls.ButtonEnums.style.GREEN

}

}

]/**SCHEMA_DIFF*/,

methods: {

runProcess: function() {

var activeRowId = this.get("Id");

var args = {

sysProcessName: "UsrMyProcess",

parameters: {

OppID: activeRowId

}

};

ProcessModuleUtilities.executeProcess(args);

}

},

rules: {}

};

});

Спасибо вот это вот работает!!!!

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

Я бы хотел сделать такую кастомизацию. Мне нужны два параметра, используемые в объектах недвижимости и листингах, по которым происходит подбор заявок. Эти параметры справочные и связаны друг с другом.
По аналогии со справочником Источник лида, в котором 3 поля. Источник, канал и описание. При этом в поле Канал – это значения из справочника Канал.

Хочу сделать справочник Районы с такими полями:
Название поля Описание
Город Это поле ссылается на справочник Город
Район Это поле, которое наполняется значением районов для конкретного города

Второй справочник такой:
Название поля Описание
Район Это поле ссылается на справочник Районы
Массив Это поле, которое наполняется значением массивов (микрорайонами) для
конкретного района
Границы В этом поле хранятся координаты точек (широта, долгота) полигона,
задающего границы массива

Когда я выбираю значение в поле Город при создании объекта – поле Район фильтруется по колонке Город (тот, что указан в поле Город объекта)
Когда я выбираю значения поля Массив – его значения тоже фильтруются по полю Район.

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

Нравится

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

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

Данная задача может быть реализована бизнес-правилами на странице.
Подробнее о бизнес-правилах можно прочитать по ссылке:
https://academy.terrasoft.ru/documents/technic-sdk/7-9/primer-primeneni…

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

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

Версия 7.9 sales.

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

Или быть может, можно создать такой раздел без реестра (ну как например, есть раздел Итоги, где вообще нет типовой таблицы с колонками)?

Нравится

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

Да это возможно, посмотрите реализацию на примере раздела "Планирование"
(CoreForecast 7.8.0) см. схема ForecastPage (она же страница раздела) является наследником "Базовая схема карточки ( NUI )"
В таком случае раздел необходимо вручную регистрировать в БД
это тема для отдельного разговора, но именно карточка страницы раздела регистрируется
в таблице SysModule, колонка SectionModuleSchemaUId
страница редактирования в SysModuleEdit - колонка "CardSchemaUId", куда необходимо будет установить соответствующие UID схемы страницы.

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

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

Версия 7.9 sales.

Есть типовая деталь с колонками, к ней подключён фильтр:

"UsrSchema4Detailefdea15b": {
                "schemaName": "UsrSchema4Detail",
                "entitySchemaName": "UsrRequest",
                "filter": {
                        "detailColumn": "UsrOrder",
                        "masterColumn": "Id"
                },
                "filterMethod": "UsrRequestFilterSupplier"
        },

который реализован следующим образом:

UsrRequestFilterSupplier: function() {
                                var filterGroup = new this.Terrasoft.createFilterGroup();
                                filterGroup.logicalOperation = Terrasoft.LogicalOperatorType.AND;
                                filterGroup.add(
                                        "OrderFilter",
                                        this.Terrasoft.createColumnFilterWithParameter(
                                                this.Terrasoft.ComparisonType.EQUAL,
                                                "UsrOrder",
                                                this.get("Id")
                                        )
                                );
                                filterGroup.add(
                                        "UsrRequestFilter",
                                        this.Terrasoft.createColumnFilterWithParameter(
                                                this.Terrasoft.ComparisonType.EQUAL,
                                                "UsrTypeRequest",
                                                "38cc7931-7db6-4e12-a343-1033f6316cf1"
                                        )
                                );
                                return filterGroup;
                        },

То есть выводятся только те записи, у которых колонка UsrTypeRequest соответствует нужному id.

Вопрос - можно ли такой же фильтр сделать динамическим? То есть допустим создаём на карточке поле с выбором из справочника с теми же значениями, что и у UsrTypeRequest, и нужно, чтобы при изменении этого поля у нас менялись отображаемые записи на детали.

Нравится

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

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

Можно сделать следующее:
1) Создать виртуальное поле на странице MyField:
MyField: {
dataValueType: Terrasoft.DataValueType.GUID,
type: Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN
},
2) Значение поля завязать на изменение справочного поля (через атрибуты страницы):

"MyField": {
	dependencies: [
		{
			columns: ["TheSameUsrTypeRequestValues"],
			methodName: "updateMyField"
		}
	]
}

Метод updateMyField должен устанавливать в поле MyField значение поля TheSameUsrTypeRequestValues.

Поле TheSameUsrTypeRequestValues - содержит те же значения, что и UsrTypeRequest.

3) Создать завязку на поле MyField:

this.Terrasoft.createColumnFilterWithParameter(
      this.Terrasoft.ComparisonType.EQUAL,
      "UsrTypeRequest",
      MyField
)
Показать все комментарии

Версия приложения 7.9.1
Юзкес: привязать свойство справочного поля "visible" некой карточки, к некой бизнес-логике.
Пердпринятые действия
При помощи мастера раздела, и редактора страницы на страницу контакта было добавлено новое справочное поле, н/п в карточке контакта добавлено поле "Страна" (ContactCountry)
см.вложение country.png
Далее в сгенерированной замещающей схеме с группе свойств конфигурационного объекта для поля был добавлен биндинг свойства "visible" к методу "ContactCountryVisibilityController"
и объявлен сам метод.

...
        {
                "operation": "insert",
                "name": "ContactCountrye97c8637-0ade-42fc-95e1-a37e1971b25e",
                "values": {
                        "layout": {
                                "colSpan": 12,
                                "rowSpan": 1,
                                "column": 12,
                                "row": 2,
                                "layoutName": "ContactGeneralInfoBlock"
                        },
                        "labelConfig": {},
                        "enabled": true,
                        "contentType": 5,
                        "bindTo": "ContactCountry",
                        "visible": {"bindTo": "ContactCountryVisibilityController"}
                },
                "parentName": "ContactGeneralInfoBlock",
                "propertyName": "items",
                "index": 4
        },
...

                methods: {
                        ContactCountryVisibilityController: function() {
                                if (this.get("ContactCountry") !== undefined) {
                                        return true;
                                } else {
                                        return false;
                                }
                        }
                }

Проблема:
во-первых - если поставить точку останова внутри объявленного выше метода, то код метода при загрузке страницы выполняется 6-10 раз !!!
во-вторых - во время отладки, даже если метод возвращает true (в случае когда целевое поле заполнено), то свойство всё равно не принимает необходимого значения.
(поле в любом случае остается скрытым)
Т.е. биндинг не приносит желаемого результата.

Протестировано как в on-site версии, так и в облачной демо-версии.

Нравится

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

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

Задача решается использованием бизнес-правил. Подробнее:
https://academy.terrasoft.ru/documents/technic-sdk/7-9/pravilo-bindpara…

Дело не том как можно.
Я изначально понимаю что есть три пути:

  1. 1. биндинг на атрибут
    (И дальнейшее управление значением атрибута любой бизнес-логикой имеющей к нему прямой или опосредованный, через события, доступ)
  2. 2. биндинг на метод
    (Идеальный вариант если логика нужна лишь на этапе инициализации, или если используется функционал, который надо выполнить автоматически но он так-же является полезной нагрузкой какого либо другого элемента)
  3. 3. использование конфигурационного объекта бизнес-правил
  4. (Идеальный вариант для организации сложной логики по валидации и зависимости значений и полей друг от друга на этапе заполнения данных пользователем)

У каждого из подходов есть своя ниша - где его применение наиболее эффективно, просто и т.д.

Дело в том, что один из этих способов - ведет себя не предсказуемо, и не очевидно некорректно!
Вопрос в конечном итоге сводится к плоскости: "Или я дурак, или лыжи не едут ?"
Ну и собственно ежели первое - то хочется учиться у сведующих уму разуму, если второе то чтобы специалисты ТП обратили на нее внимание.

Уточните, пожалуйста, метод ContactCountryVisibilityController вызывается в методе onEntityInitialized?

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

Бог с ней с моей самописной логикой, давайте возьмем базовую поставку

Возьмем к примеру схему BaseProfileSchema (пакет NUI - фактически ядро системы)
Где у нас имеется объявленный метод "getVisibleContent"

Возьмем карточку контрагента и воспользуемся поиском по исходным кодам, чтобы получить представление о количестве биндингов на данный метод или количество его прямых вызовов, возможного абстрагирования в других переменных и т.д. (см.вложение getVisibleContent_UsagesInContragentPage.png).
Оба биндинга принадлежат к той-же схеме "BaseProfileSchema" - это объекты "ProfileContentContainer" и "ProfileModuleActions", их свойство "visible"

Итого
во-первых: установив точку останова внутри метода getVisibleContent - во время загрузки страницы получаем 4-6 вызовов вместо положенных двух.
во-вторых: если на первом вхождении точки останова подменить вызываемую функцию, скорректировав возвращаемое ею значение
т.к. исходный код метода:
getVisibleContent: function() {
return !this.getVisibleBlankSlate();
},
Во время штатного выполнения кода getVisibleContent - возвращает "false" (т.е. забинженное на метод свойство "visible" должно устанавливаться в значение false, тем не менее элементы страницы "Добавить контакт" и "Выбрать" как раз таки отображаются см.вложение BasicFunctionality_ReturnFalse.png)
Если же мы подменим функцию this.getVisibleBlankSlate() таким образом чтобы метод getVisibleContent возвращал "true"
н/п this.getVisibleBlankSlate = function(){return false};
То несмотря на то, что метод начинает возвращать "true" - элементы как раз таки скрываются. см.вложение BasicFunctionality_ReturnTrue.png
Т.е. все с точностью да наоборот от ожидаемого поведения !
Свойство visible принимающее значение true (элемент показывается) значение false (элемент скрывается), по крайней мере если не биндить поле а указывать значение прим в описании схемы - работает по такому принципу.

Никакой разработки НОВОЙ функциональности - Это все штатные системные коды входящие в базовую поставку и их поведение в облачной демо версии!
Прошу Вас объяснить что в данном случае происходит:
1) Почему метод вызывается большее количество раз чем к нему идет обращений/биндингов ?
2) Почему реальное значение получаемое параметром - инвертировано от того что возвращается методом ?

Добрый день!
Вы немного недосмотрели.
Итак, базовая логика. Есть 2 элемента , у которых visible забайнден на getVisibleContent:

{
      "operation": "insert",
      "name": "ProfileModuleActions",
      "parentName": "ProfileModuleContainer",
      "propertyName": "items",
      "values": {
		...
		"visible": {"bindTo": "getVisibleContent"},
		...
}
{
        "operation": "insert",
	"name": "ProfileContentContainer",
	"parentName": "ProfileModuleContainer",
	"propertyName": "items",
	"values": {
		...
		"visible": {"bindTo": "getVisibleContent"},
                ...
}

Обратим внимание на свойтво name элементов: ProfileModuleActions и ProfileContentContainer
Сам метод работает так как вы и описывали. Теперь если посмотреть на клиенте в HTML коде эти элементы, то увидим, что стиль dispaly: ... соответствует значению visible элементов

То что вы на скрине показали, что элементы видны, то мне кажется, что вы обратили внимание не на свойство "name", а на свойство "parentName"

Теперь что касается нескольких входов в функцию. Всегда будет 2 входа: 1 - это при создании элемента управления происходит инициализация начального значения. 2-й - это при изменении зависимого значения, в данном случае это значение аттрибута модели, который учавствует в функции (ях), на которые произведен bind

см. https://004531-sales-enterprise.bpmonline.com
Админ
Админ
пакет Custom замещающая схема ContactPageV2 - поле UsrCity

Очевидная проблема функционала.
Функция (метод) "забинженная" на свойство поля - вызывается на исполнение 6-ть и более раз,
после чего значение свойства все равно не устанавливается в соответствии с возвращаемым ею значением.

PS: Это как раз тема моего изначального обращения (меня потом начали заворачивать по SLA пришлось искать примеры в базовых кодах)

Добрый день.
На вашей демо-версии всегдя возвращается false. Если изменить код и вставить прямо "return true", то все работает. В вашей схеме вообще нет аттрибута ContactCity, поэтому false всегда. Также, после того как вы изменили код необходимо убедится, что он обновился на клиенте, а не вычитался из кэша. Данный работает корректно, т.к. по всей системе были бы ошибки

Касательно 6 раз - это нужно исследовать, и это уже отдельная история. Именно с темой "метод вызывается 6 раз" вы можете обратится в службу поддержки

Артем, демку разворачивал в "попыхах" действительно допустил опечатку в методе.
Но сути дела это не меняет, я исправил ошибку.


Метод проверяет не атрибут, а поле - его заполненность.
Вот пример 2 контакта у одного поле "Город" (UsrCity) заполнено у другого - нет.

Установим точку останова в методе CityVisibleController
Заходим в карточку контакта - поле которого заполнено:

Мало того что метод вызывается 6-ть раз, смотрим на логику, метод возвращает "true", поле "Город"
в карточке показывается - пока что кажется что все идет нормально, но давайте зайдем в карточку контакта у которого это поле не заполнено:
И ТУТ ВНИМАНИЕ !!!
Браузер Mozilla Firefox

this.get("UsrCity") почему-то возвращает не undefined а пустую строку ""
Браузер Google Chrome

В том же самом месте - возвращает UNDEFINED! (Как и ожидалось)
Какого лешего ? извините за выражение.
И даже в Google Chrome где this.get("UsrCity") возвращает undefined и моя логика срабатывает, т.е. методо возвращает FALSE
ВСЕ РАВНО ПОЛЕ UsrCity остается видимым !

Итак.
Поле из БД приходит нам в схему и ложится в аттрибут. Таким образом чтение/запись аттрибутов и полей одинаковая (this.get() / this.set())

Теперь о undefined и ''.
Мы знаем, что в БД не может хранится значение undefined, поэтому это сравнение некорректное. Оно может быть undefined только тогда, когда вы создаете новую запись, у вас создается модель, которая не содержит значений аттрибутов. Т.е., если для новой записи написать this.get('поле'), то значение будет undefined (если конечно же кто-то в фоне не установил этот аттрибут). После значения всех атррибутов, которые являются "колонками/полями" записывается в БД.
В нашем приложении для полей типа "текст" нельзя записывать в БД значения null (not null) и записывается значение по умолчанию - пустая строка. Поэтому, во время редактирования какой-то записи вам вычитается пустая строка и это значение ляжет в аттрибут. Отсюда у вас и разногласия в значениях

Хорошо, мы пробовали изменить проверку на более корректную, как нам казалось
Т.к. в примерах с сайта академии мы видели проверку поля на пустоту специальным методом this.Ext.isEmpty
т.е. буквально переписали метод следующим образом:

CityVisibleController: function() {
	var UserCity = this.get("UsrCity");
		if (this.Ext.isEmpty("UsrCity")) {
			return false;
		} else {
			return true;
		}
	}

Опять же во время отладки, чтобы не содержалось в this.get("UsrCity") - undefined или "" или поле заполнено и там возвращается объект - вердикт метода всегда FALSE (т.е. на undefined и на "" тоже, это как-бы получается "не пустое" поле а какое-же оно ?)

PS: В конечном итоге добились требуемой функциональности вот так:

CityVisibleController: function() {
	var UserCity = this.get("UsrCity");
	if (UserCity !== undefined && UserCity !== "" && UserCity !== 0) {
		return true;
	} else {
		return false;
	}
}

Т.е. проверяя на все подряд, и даже на всякий случай на 0
А так же выяснили что во время 12-ти вызовом метода, в первых 6-ти - this.get("UsrCity") - undefined
А в последних 4-х уже возвращает пустую строку "" (и вот видимо во время одного из таких вызовов и происходит биндинг)

Так что вопрос ПОЧЕМУ метод вызывается 12-ть раз остается открытым.
Вот еще вопрос, юзкейс: свойство биндится на какую-то тяжелую логику включающую в себя ESQ запросы в БД - получается они будут выполнены 12-ть раз ?!
Это баг или фича ? :)

В поддержку даже нет смысла обращаться - будет отклонен по SLA как "пить дать".

Добрый день!
Певрое. Так как это JS, то вы можете использовать следующее выражание - return !!!this.get("UsrCity"),
так как !! от undefined и пустой строки вернет false.
Второе. Касательно 12 раз. Еще раз, каждый аттрибут инициализируется с каким-то значением, потом начинается цепочка зависимостей, в ходе которых происходят еще вызовы этого метода. Вы это можете увидеть в call stack'е.
Третье. Касательно тяжелого ESQ. Вы немного не разобрались. Составление ESQ - синхронная "операция", а получение данных - асинхронная. У вас просто не получится внутрь bind'а "впихнуть" асинхронность. Обычно все байнды завязываются на значения аттрибутов, их комбинаций, клиентской логики, а значение самиъх этих аттрибутов может быть установленно в callback'е любой логики

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

Добрый день, подскажите пожалуйста, как в бизнес-процессе передавать параметры в шаблон письма при отправке html email-шаблона через действие “Отправить e-mail”. Шаблон выбираю через формулу:

[#Читать данные 2.Первый элемент результирующей коллекции.Тело#]


Шаблон успешно отправляется, однако при задании макросов в самом шаблоне, адресату приходит в письме просто текст с формулуй:
Здравствуйте, [#Адресат.ФИО#], и если задать формулу из БП аналогичный результат: Здравствуйте, [#Читать данные 1.Первый элемент результирующей коллекции.ФИО#]

 

Нравится

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

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

В текущей версии продукта сформировать тело и тему письма по шаблону можно только в продуктах линейки Service. Пример формирования вы можете посмотреть в процессе "Процесс отправки уведомления контакту обращения".

В будущих версиях приложения появится возможность использовать любой шаблон при отправке письма элементом "Отправить email".

Временно для формирования письма по шаблону с использованием параметров процесса вы можете использовать статью:
http://www.community.terrasoft.ua/blogs/12527

Демьяник Алексей пишет:

Временно для формирования письма по шаблону с использованием параметров процесса вы можете использовать статью: http://www.community.terrasoft.ua/blogs/12527

а где бы найти актуальную ссылку на эту статью?



Новый элемент "Отправить email" не всё позволяет сделать, а необходимо это сделать как раз не в Service 

Статья тут.

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