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

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

TypeError: rootItem is undefined 1 ViewModelSchemaValidationMixin.js:52:1

И дальше перечисление стека вызовов.

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

Нравится

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

Александр, здравствуйте!

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

Спасибо, Илья.

Да, дело было в текущем пакете. Спасибо.

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

Добрый день.
У меня такая проблема: по БП пользователю ставиться задача, но ее может закрыть любой другой пользователь, а нужно, чтобы только ответственный мог ее закрыть. В правах доступа настроено следующем образом: Раздел Активность: администрирование по записям(права на изменение) - указано кто создает и кому дается право. Если зайти в раздел "Активности" и там начать закрывать задачу, то Система не даст это сделать, а если это делать через объект "Продажа" через БП, то все возможно. Может кто-то подскажет как решить данную проблему? Я не программист, поэтому много не понимаю, но решить как-то хочу проблему. Заранее спасибо!

Нравится

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

А каким образом вы через объект Продажа, закрываете активность?

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

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

Смотрите в сторону настройки прав доступа - необходимо настроить администрирование по записям для объекта "Активность".
Решением будет включение администрирования (по умолчанию оно включено) и удаление всех строк из настроек по умолчанию для изменения - это будет значит, что менять задачу может только автор/ответственный.

"Демьяник Алексей" написал:
...что менять задачу может только автор/ответственный.

Но Татьяна говорит о том, что закрыть активность должен иметь возможность только ответственный.

"D.T." написал:
Демьяник Алексей пишет:

...что менять задачу может только автор/ответственный.

Но Татьяна говорит о том, что закрыть активность должен иметь возможность только ответственный.

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

Аналогичный процесс нужно сделать на изменение активности.

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

Если закрытие происходит в рамках бизнесс-логики только через UI
(графический интерфейс, т.е. не бывает/пердусмотрено, так что закрывается например в другом БП)
То задачу можно решить на уровне JS-логики карточки Активности (Задачи).
Для того чтобы не "мучаться" определяя входит ли пользователь в необходимую функц.роль или организационный юнит и т.д. можете использовать разработанный мной миксин

Спасибо всем за ответы. Буду пробовать. Отпишусь по результатам.

"Демьяник Алексей" написал:Сделайте процесс, который при создании активности будет забирать права у всех и выдавать только ответственному.

Не совсем логично, так как автору надо оставить возможность менять содержание задачи (или отменять её)

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

Добрый день.
Занимаюсь реализацией интеграции с BPM'Online 7.10 через DataService.

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

Код примерно такой

var list = new Dictionarystring, ColumnExpression>();
foreach(....)
{

        list.Add(c1.Attribute.FieldName, new ColumnExpression()
        {
                ExpressionType = EntitySchemaQueryExpressionType.Parameter,
                Parameter = new Parameter()
                {
                        Value = value,
                        DataValueType = c1.Attribute.DataType
                }
        });
}

var insertQuery = new InsertQuery()
{
        RootSchemaName = EntityName,
        ColumnValues = new ColumnValues()
};
insertQuery.ColumnValues.Items = new Dictionarystring, ColumnExpression>(list);

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

Позже я пытался вместо объекта DataTime передавать строку с форматированием которое указано в https://community.terrasoft.ru/forum/topic/24597 , но это так же не помогло.

1) Подскажите, пожалуйста, как работать с полями дата и время?
2) Есть ли способ чтобы DataService выдавал более UserFrendly ошибку чем "Удаленный сервер возвратил ошибку: (500) Внутренняя ошибка сервера."? Т.к. выяснение того, что ошибка связана именно с типом DataTime заняло много времени, причем формат запроса корректен и "вроде бы" DataService не должен ругаться на него 500 ошибкой...

Нравится

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

Добрый день!

Для передачи даты через DataService формат должен быть следующий : [""\""2000-12-31T09:41:59\""""""""]. Например:

[quote="Мотков Илья"]

Добрый день!

Для передачи даты через DataService формат должен быть следующий : [""\""2000-12-31T09:41:59\""""""""]. Например:

"Габбазов Искандер Рустемович" написал:На сколько я понимаю ваш пример это кусок "правильного" JSON'а.

нет, JSON тут совсем не при чем.
Это текстовое представление формата TimeStamp,
Оператор @ - интерпритирует строку без управляющих последовательностей, ну и двойные кавычки "схлопываются" по две в одну, на выходе имеем

const string startDate = @"""\""2000-12-31T09:41:59\"""""""""";

Добрый день, Илья!

Другим Ильей :) формат указан правильный:
[quote="Мотков Илья"]
const string startDate = @"""\""2000-12-31T09:41:59\"""""""""";

значение

@"""\""2000-12-31T09:41:59\"""""""""";

Илья, нет, формат все же верный, то есть тайм-стамп в экранированных кавычках, и в кавычках. Я не имел ввиду, что это должен быть валидный json, это просто формат, в виде которого по определенным архтиктурным причинам передается дата в приложении.

"Кот Владимир Владимирович" написал:то есть тайм-стамп в экранированных кавычках, и в кавычках.

вот, смысл прояснился :) понятно, спасибо за пояснения.

На данный момент сделал так:

switch (t.Name)
{
	...
 
	case "DateTime":
		value = @"""\""2000-12-31T09:41:59\"""""""""";

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

var date = DateTime.Now;
 
insertQuery.ColumnValues.Items.Add("....", new ColumnExpression()
{
	ExpressionType = EntitySchemaQueryExpressionType.Parameter,
	Parameter = new Parameter()
	{
		Value = "\""+date+ ""\""""
Показать все комментарии

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

Версия 7.10 sales.

При эскалации обращения открывается отдельная страница, её схема EscalationEditPage, объект - то же самый Case.

При этом доступны не все колонки объекта Case. В частности, не доступна колонка Id, а также пользовательские колонки (при попытке вывести значение в консоль после onEntityInitialized выводится undefined).

Как получить данные пользовательских колонок?

Задача в общем: в зависимости от значения одной из пользовательских колонок автоматически проставлять группу ответственных.

Нравится

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

Попробовал передавать через сообщения:

На странице casePage внутри runEscalation добавил:

this.sandbox.publish("setCaseType", this.get("UsrCaseType"), [this.sandbox.id + "_EscalationEditPage"]);

И подпись на сообщение внутри init на странице эскалации.

Не помогло.

Как вообще формируется страница эскалации?

Решил задачу.

Просто проставляю группы ответственных уже на уровне Обращения. При открытии эскалации они копируются.

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

Зачастую требуется корректировать набор фильтров для справочных полей карточки как говорится "на лету", в зависимости от тех или иных условий/событий/действий пользователя

Собственно к коллекции фильтров можно подступиться через
this.columns.{ИмяКолонки}.lookupListConfig
Но основной вопрос - корректно ли манипулировать этой коллекцией через непосредственный доступ - вот таким образом, или разработчик предусмотрел другую методику корректировки набора фильтров для справочных полей ?
Специализированные методы возможно,
Возможно состояние this.columns.{ИмяКолонки}.lookupListConfig в жизненном цикле контекста может быть сброшено - и необходимо иметь вспомогательные сущности, для повторного его построения. (Т.к. изначально тот-же lookupListConfig задается например при описании атрибута одноименного колонке, но в конечном итоге среди полей получаемых из модели по имени поля - не содержится) ?

Нравится

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

Не встречал такого подхода работы в рамках базовых конфигураций.
Если вам необходимо анализировать внешние асинхронные условия пере формированием той или иной логики фильтр метода, то рекомендуем вам:
1. Сделать подписку на изменения всех колонок, которые могут влиять на логику формирования фильтрации колонки в lookupListConfig;
2. При изменении данных колонок кешировать асинхронный результат, который должен повлиять на логику фильтрации в атрибутах;
3. В фильтр методе lookupListConfig-а: анализировать кешированные атрибуты, и формировать согласно вашей логики нужный вам esq, блоками if else.

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

7.10
Для примера возьмем Lead
Создаем в схеме карточки (LeadPageV2)

                attributes: {
                        "firstAttr": {
                                type: Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN,
                                dataValueType: Terrasoft.DataValueType.BOOLEAN,
                                value: false
                        },
                        "secondAttr": {
                                type: Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN,
                                dataValueType: Terrasoft.DataValueType.BOOLEAN,
                                value: false
                        },
                        "depAttr": {
                                "dependencies": [
                                        {
                                                "columns": ["secondAttr", "firstAttr"],
                                                "methodName": "depMethod"
                                        }
                                ],
                                type: Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN,
                                dataValueType: Terrasoft.DataValueType.BOOLEAN,
                                value: false
                        }
                },
                methods: {
                        "onEntityInitialized": function() {
                                document.LeadPageScope = this;
                                this.callParent(arguments);
                         },
                        "depMethod": function() {
                               alert("Dep Trigged!!!")
                         }
                }

Создаем в схеме секции (LeadSectionV2) почти идентично
                attributes: {
                        "firstAttr": {
                                type: Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN,
                                dataValueType: Terrasoft.DataValueType.BOOLEAN,
                                value: false
                        },
                        "secondAttr": {
                                type: Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN,
                                dataValueType: Terrasoft.DataValueType.BOOLEAN,
                                value: false
                        },
                        "depAttr": {
                                "dependencies": [
                                        {
                                                "columns": ["secondAttr", "firstAttr"],
                                                "methodName": "depMethod"
                                        }
                                ],
                                type: Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN,
                                dataValueType: Terrasoft.DataValueType.BOOLEAN,
                                value: false
                        }
                },
                methods: {
                        "init": function() {
                                document.LeadSectionScope = this;
                                this.callParent(arguments);
                         },
                        "depMethod": function() {
                               alert("Dep Trigged!!!")
                         }
                }

Открываем карточку Лида в Combined режиме,
Устанавливаем точки останова внутри метода depMethod в карточке и секции соответственно,
Открываем консоль, поехали

document.LeadSectionScope.set("firstAttr", true);
//НИЧЕГО НЕ ПРОИСХОДИТ !
//Исполнение в метод depMethod секции не переходит.
document.LeadPageScope.set("firstAttr", true);
//ОТЛАДЧИК ВСТАЕТ ВНУТРИ МЕТОДА depMethod карточки !

И как это понимать ?
Двойные стандарты для функциональности атрибутов в отношении зависимостей ?

Нравится

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

Здравствуйте, Илья.

Зависимости атрибутов представляют собой зависимости между колонками конкретной записи. При изменении значения колонки в карточке редактирования срабатывает зависимость.
Раздел в свою очередь работает с коллекцией записей. Нет конкретной колонки, изменения которой должно вызвать срабатываение зависимости.

Ну в рамках карточки мы не обязательно привязаны к колонкам,
мы можем просто создать атрибуты (свои, пользовательские не связанные с колонками - что собственно и показано в примере) и на их изменение - зависимости выраженные в вызове методов текущего контекста.
Почему то же самое с атрибутами не доступно в рамках карточки секции ?
Возможно есть иной способ привязки логики к изменению атрибута ?
Например биндинг value на метод:
Что в таком случае будет происходить -
При установке значения в аттрибут - каждый раз будет вызываться забинженный метод - в аргументы которого будет поступать устанавливаемое значение, а его return значение - будет установлено в качестве текущего value ?

Потому что applyDependencies из BusinessRulesApplierV2 работает только для BasePageV2 и её наследников. По сути это сахар над обычным бекбоновским this.on("change: ...
так что в секции можете в ините просто написать:
this.on("change:MyAttrColumn", this.myMethod, this);
где MyAttrColumn имя атрибута\колонки для которой будет тригерится по изменению метод myMethod описанный в блоке методов.

"Максим Шевченко" написал:По сути это сахар над обычным бекбоновским this.on("change

ну вот именно это я и подразумевал :)
Спасибо что уточнили.
А можно подключить applyDependencies из BusinessRulesApplierV2 в качестве зависимостей схемы секции - в таком случае тоже будет работать ?
Просто интересует однообразие.

Прям её не подключить, все же в базовой реализации этого метода анализируется атрибут IsEntityInitialized которого нет в секции. Но, вы можете попробовать написать свой миксин который будет пробегать по атрибутам, искать у них свойство "зависимости" и делать в этом форе this.on на указанные методы.

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

Может кто-нибудь сталкивался с подобной проблемой.
Использую LookupUtilities:

var config = {
        entitySchemaName: "UserReport",
        columns: ["Id", "Name", "Parameters", "ReportSchemaUId"],
        multiSelect: false,
        actionsButtonVisible: false,
        lookupPageName: "LookupPage"
};
LookupUtilities.Open(this.sandbox, config, this.onReportSelected, this, null, false, false);

Все красиво, и работает корректно. Открывается окно выбора ().
Но предположим, что мне необходимо добавить дополнительную кнопку, либо изменить страницу LookupPage.
Что я делаю - наследую LookupPage.
define("CustomLookupPage", [],
        function() {
                return Ext.define("Terrasoft.configuration.CustomLookupPage",
                        {
                                extend: "Terrasoft.LookupPage",
                                alternateClassName: "Terrasoft.CustomLookupPage"
                        }
                );
        }
);

Затем, меняю config.lookupPageName = "CustomLookupPage".

var config = {
        entitySchemaName: "UserReport",
        columns: ["Id", "Name", "Parameters", "ReportSchemaUId"],
        multiSelect: false,
        actionsButtonVisible: false,
        lookupPageName: "CustomLookupPage"
};
LookupUtilities.Open(this.sandbox, config, this.onReportSelected, this, null, false, false);

Но теперь, при открытии получаю ошибку (
).
Что-то попало в бесконечный цикл, вижу ошибку переполнения стэка.

Как такое лечится?

Нравится

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

Добрый день, Евгений!

Не понятно, что могло вызвать такой странный результат. Я бы порекомендовал обратиться в support Террасофта, пускай посмотрят.

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

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

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

"Севостьянов Илья Сергеевич" написал:

Спасибо за идею, на первой неделе мая попробую реализовать и отпишусь!

Вообщем Вы были изначально на правильном пути, но упустили несколько моментов, по сути Ваши начинания "в купе с моей идеей" и есть итоговое решение, т.к. наследование на уровне схем все равно оказалось необходимым условием (правда через зависимости, а не механизм наследования)
Разобраться помогла схема "MultiLookupModule" входящая в базовую поставку
1) Вы реализуете модуль, зависимости которого необходимо указать не только в исходном коде но и в меню структуры

2) Сам модуль не должен быть чьим либо наследником, всё необходимое идет в его зависимости, в т.ч. и LookupPage который мы идеологически наследуем, но архитектурно через наследование в схемах - это почему-то не работает (Если у казать "Выбор из справочника" как родителя - получаем очень много разного рода ошибок при вызове).
3) Далее вот вообщем-то пример самого кода

define("MyCustomLookupPage", ["LookupPage", "LookupPageViewGenerator", "LookupUtilities", "css!LookupPageCSS"],
	function(LookupPage, LookupPageViewGenerator) {
		return Ext.define("Terrasoft.configuration.KmGMSLookupPage", {
			alternateClassName: "Terrasoft.KmGMSLookupPage",
			extend: "Terrasoft.LookupPage",
			gridWrapClasses: ["my-custom-lookup-control"]
		});
	});

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

var config = {
        entitySchemaName: "Lead",
        columns: ["Id"],
        multiSelect: false,
        actionsButtonVisible: false,
        lookupPageName: "MyCustomLookupPage"
};
this.openLookup(config, function(result){console.log(result)})

Вот.

PS:
Были попытки отнаследовать через механизм наследования схем, насколько хватило фантазии и времени - но все безрезультатны.
Хотя очень хотелось бы вот так вот взять и в diff все свои вынести изменения.
Тем не менее описанный способ, предположительно - позволяет делать то что нужно...

"Севостьянов Илья Сергеевич" написал:

Как оказалось - решение было близко)
Спасибо большое, что поделились окончательной реализацией! Я то уже переключился на более приоритетные задачи, так как посчитал эту затею бесперспективной.

На самом деле - решение не окончательное... бой продолжается :)
Есть прям несколько моментов - которые весьма и весьма удивляют... например что кнопки по факту "захардкожены" в LookupPageViewGenerator и собственно не зависят от каких либо конфигурационных параметров вызова этого самого генератора, что приводит к необходимости наследовать и его, с переопределением некоторых функций, в свою очередь "копия" генератора подобным образом не работает полностью или частично, т.к. используя наследника в качестве зависимости - получаем ряд ошибок про "sunbox of undefined" из core.js (что практически убивает надежду "по быстрому разобраться") при попытке выбора записей из такого справочника и т.д.

Кстати по какой-то причине не удается подключить к карточке страницы LookupUtilities
В конечном итоге в контексте карточки нет объекта "LookupUtilities"

define("MyCustomPage", ["LookupUtilities"],
	function(LookupUtilities) {
...

В конечном итоге в контексте карточки LookupUtilities - undefined

Не поделитесь, как вы подключали LookupUtilities к странице ?
(Я уже и в dependecies структуры добавил его, так же безрезультатно)

Там необходимо использовать V2

define("MyCustomPage", ["LookupUtilitiesV2"],
        function(LookupUtilities) {
...

Победа.

Кастом окна справочника через наследование его базового Ext-класса возможен, и даже, как оказалось не сложен.

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

1) Создаем пользовательский модуль например "MyCustomLookupWindow"
[color=red]Внимание![/color]

  • Модуль не должен являться чьим либо наследником
  • В структуре метаданных модуля, дублируем зависимости, которые объявим в самом листинге

  • схемы при создании необходимо выбирать по заголовкам (давняя боль), облегчаю задачу:
    LookupPage - Выбор из справочника ( NUI )
    LookupPageCSS - Стили модуля справочника ( NUI )
    LookupPageViewGenerator, LookupUtilities, MaskHelper - имеют такие же заголовки как и их имена

define("MyCustomLookupWindow", ["LookupPage", "LookupPageViewGenerator", "LookupUtilities", "css!LookupPageCSS"],
	function(LookupPage, LookupPageViewGenerator) {
		return Ext.define("Terrasoft.configuration.MyCustomLookupWindow", {
			alternateClassName: "Terrasoft.MyCustomLookupWindow",
			extend: "Terrasoft.LookupPage",
			gridWrapClasses: ["km-gms-lookup-control"]
		});
	});

2) Для вызова lookup-наследника используйте в вашей логике this.openLookup метод (присутствует в контексте любой карточки/схемы/детали), если же случилось так что его нет - то см.выше - надо будет подключить LookupUtilitesV2 в зависимости схемы, и использовать метод Open предоставляемый объектом зависимости. (Примеры использования см.в исходниках и в начале темы)

//Подготовим минимальный конфигурационный объект
var config = {
        //Для примера справочник "нацелен" на раздел "Лиды"
        entitySchemaName: "Lead",
        columns: ["Id"],
        multiSelect: true,
        actionsButtonVisible: true,
        //Вот сюда передаем имя модуля-наследника
        lookupPageName: "MyCustomLookupWindow"
};
//пример вызова
this..openLookup(
         //наш конфигурационный объект
         config, 
         //callback принимающий результат/результаты выбора в виде коллекции 
         function(selected){console.log(selected)},
         //контекст для коллбэка
         this
)

3) Для того чтобы закастомить кнопки необходимо в нашем наследнике переопределить метод renderLookupView
в который произвести инъекцию своей логики

define("MyCustomLookupWindow", ["LookupPage", "LookupPageViewGenerator", "LookupUtilities", "css!LookupPageCSS"],
	function(LookupPage, LookupPageViewGenerator) {
		return Ext.define("Terrasoft.configuration.MyCustomLookupWindow", {
			alternateClassName: "Terrasoft.MyCustomLookupWindow",
			extend: "Terrasoft.LookupPage",
			gridWrapClasses: ["km-gms-lookup-control"],
			//Переопределяем метод в котором мы можем управлять сформированной конфигурацией до рендеринга.
			renderLookupView: function(schema, profile) {
				var config = this.getLookupConfig(schema, profile);
				var topPanelConfig = LookupPageViewGenerator.generateFixed(config);
				//----------------------- инъекция логики (начало) ----------------------
				//переменная для хранения ссылки на массив объектов-конфигурайий кнопок	
				var buttonsConfig;
				//Получаем ссылку на аттрибут-массив конфигурационных объектов-кнопок
				//Используем Underscore.some с возможностью прерывания переборы по возврату от предиката "true"
				_.some(topPanelConfig.items, function(target) {
					//выделяем объект группы кнопок (Wrapper) по id контейнера
					if (target.id === "selectionControlsContainerLookupPage") {
						//в нем ищем подчиненные объекты являющиеся массивом
						_.some(target, function(target) {
								//согласно структуры конфигурационного объекта панели
								//"чистым" массивом является только объект с конфигами кнопок
							if (Array.isArray(target)) {
								//сохраняем ссылку на него в переменной для дальнейшего использования
								buttonsConfig = target;
								//Прерываем перебор
								return true;
							}
						});
						//Прерываем перебор
						return true;
					}
				});
				//Создаем новую кнопку, клонируя любую, первой как правило идет кнопка "Отмена"
				var newButton = Terrasoft.deepClone(buttonsConfig[0]);	
				//Используем Underscore.extend для объединения склонированного объекта
				//с анонимным объектом-разницы в котором опишем необходимые изменения
				_.extend(
					newButton,
					{
						caption: "Добавленная кнопка",
						click: {
							bindTo: "AddTender"
						},
						//Внимаение! свойство "tag" должено быть уникальным для каждой кнопки
						tag: "AddTender",
						//меняем стиль
						style: "green"
					}
				);
				//Добавляем конфигурационный объект кнрпки в массив конф.объектов
				buttonsConfig.push(newButton);				
				//Поиск конфигурационного объекта кнопки "Выбрать" в искомом массиве по caption
				_.some(buttonsConfig, function(target) {
					if (target.caption === "Выбрать") {
						//В найденном объекте меняем значение аттрибута caption на "Создать тендеры".
						target.caption = "Переименованная кнопка" ;
						return true;
					}
				});
				//Поиск конфигурационного объекта кнопки "Добавить" в искомом массиве по caption
				_.some(buttonsConfig, function(target) {
					if (target.caption === "Действия") {
						//В найденном объекте меняем значение аттрибута visible на "false"
						//тем самым скрывая кнопку-меню
						target.visible = false ;
						return true;
					}
				});
				//----------------------- инъекция логики (конец) ----------------------
				this.renderLookupControls(config, topPanelConfig);
			}
		});
	});

Вот какое-то такое получится окно

Классно и подробно - хоть в официальный SDK добавляй! :)

Илья,

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

Севостьянов Илья Сергеевич, спасибо за подробность, как раз искал подобный кейс

Севостьянов Илья Сергеевич,

Скажите пожалуйста а где вызвать метод 

this.openLookup, я никак не могу реализовать пример. 

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

Собственно вопрос:
Существует ли способ определить, есть ли подписчики у события, до его публикации ?

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

Нравится

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

Вы же имеете в виду sandbox? Если да, то да. Подключите кор, у него есть переменная observable, там есть все события и списки их подписчиков:

define("ContactPageV2", ["core"], function(core) {
	return {
		entitySchemaName: "Contact",
		details: /**SCHEMA_DETAILS*/{}/**SCHEMA_DETAILS*/,
		diff: /**SCHEMA_DIFF*/[
		]/**SCHEMA_DIFF*/,
		methods: {
			init: function() {
				this.callParent(arguments);
				document.scope = this;
				document.coreScope = core;
			}
		},
		rules: {},
		businessRules: /**SCHEMA_BUSINESS_RULES*/{}/**SCHEMA_BUSINESS_RULES*/
	};
});

Большое спасибо, за "раскрытый прием" - открывает много возможностей по построению еще более интересной бизнес-логики.

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

При попытке зайти в систему как обычно, через NuiLogin.aspx выдает ошибку:

POST http://localhost:82/ServiceModel/AuthService.svc/Login 404 (Not Found)

При этом при использовании Login.aspx заходит без проблем.
Подскажите в чем дело?

Нравится

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

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

Предположительно некорректно развернут сайт.
Попробуйте переразвернуть приложение согласно инструкции https://academy.terrasoft.ru/documents/sales-enterprise/7-10/ustanovka-…

Похоже на то что в конфигах указаны https хотя сайт развернут в ис поверх http, протоколы должны соответствовать.
Статья:
https://academy.bpmonline.com/documents/marketing/7-9/switching-http-ht…

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

Во время брожения по исходным кодам наткнулся:

this.sandbox.publish("MoveScopeToCombinedMode", this, ["MoveScopeToCombinedMode"]);

Уж очень интригующе называются литералы :)
Кто ни будь знает суть происходящего... "скоупы" можно/нужно перемещать между режимами ?

Нравится

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

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

Напишите название модуля в котором нашли такой код, а также версию и название продукта.

Прошу прощения за поднятую панику :)
Это собственно "костыль" собственного производства...
Достался от предшественников, они разблокировали схемы типовой поставки и вносили в них изменения (зачем-то :) )

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