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

Система версии 7.10.1.1161
Есть карточка заказа и есть кастомная страница подборщика продуктов, которая открывается из карточки заказа по нажатию на специально созданную кнопку. Кастомная страница унаследована от BasePageV2 и привязана к entitySchema Order (то есть к тому же объекту, что и карточка заказа). На ней используется стандартная кнопка Закрыть. Все прекрасно работает, кроме случая когда подборщик открываем из карточки ново создаваемого заказа(add). В этом случае при нажатии Закрыть на кастомной странице выбрасывает обратно в раздел, а должно бы в карточку заказа.

Обратил внимание, что при добавлении нового заказа когда открывается карточка редактирования, то хеш все равно остается от раздела - SectionModuleV2/OrderSection (аналогично и во всех остальных разделах). Вероятно, в этом и есть причина, так как при нажатии Закрыть публикуется BackHistoryState. Ниже код, который используем для открытия карточки подборщика. Подскажите как добиться нужного эффекта, так как кейс с открытием подборщика из нового заказа и есть самый основной.

                                openProductSelector: function() {
                                        var orderId = this.get("PrimaryColumnValue") || this.get("Id");
                                       
                                        var defaultValues = [
                                                        {
                                                                name: "PrimaryColumnValue",
                                                                value: orderId
                                                        },
                                                        {
                                                                name: "UseSeparatedPageHeader",
                                                                value: true
                                                        }

                                                ];
                                       
                                        stateObj = {
                                                                        isSeparateMode: true,
                                                                        schemaName: "SelectProductInOrderPage",
                                                                        moduleId: "CardModuleV2_SelectProductInOrderPage",
                                                                        valuePairs: defaultValues,
                                                                        operation: "open",
                                                                        isInChain: false
                                                                };
                                        requestUrl = "CardModuleV2/SelectProductInOrderPage/";
                                       
                                        this.sandbox.publish("PushHistoryState", {
                                                hash: requestUrl,
                                                stateObj: stateObj
                                        });
                                },     

                                onProductSelectionButtonClick: function() {
                                        this.set("OpenselectProductPage", true);
                                        this.save({isSilent: true});
                                },

                onSaved: function (response, config) {
                    this.hideBodyMask();
                    if (!this.get("NextPrcElReady")) {
                        this.set("NextPrcElReady", response.nextPrcElReady);
                    }
                    if (config && config.isSilent) {
                        this.onSilentSaved(response, config);
                    } else {
                        var updateConfig = this.getUpdateDetailOnSavedConfig();
                        this.sandbox.publish("UpdateDetail", updateConfig, [this.sandbox.id]);
                        this.sendSaveCardModuleResponse(response.success);
                        if (this.get("IsInChain")) {
                            this.onProcessCardSaved();
                            return;
                        }
                        if (this.isNewMode()) {
                            this.onCloseCardButtonClick();
                        } else {
                            this.onProcessCardSaved(true);
                        }
                    }
                    this.set("Operation", Terrasoft.ConfigurationEnums.CardOperation.EDIT);
                    if (!this.destroyed) {
                        this.updateButtonsVisibility(false, { force: true });
                    }
                    this.set("IsChanged", this.isChanged());
                    this.subscribeOwner(config);
                    if (config && config.isSilent) {
                                                if(this.get("OpenselectProductPage")) {
                                                        this.set("OpenselectProductPage", false);
                                                        this.openProductSelector();
                                                }
                        return;
                    }
                    this.updateAmountAfterSave("ProductInProductsTab",
                        function () {
                            this.updateDetail({ detail: "ProductInResultsTab" });
                            this.updateOrderProductSummary();
                        },
                        this
                    );
                },

Нравится

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

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

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

Илья, но я ведь и делаю save перед открытием. И делаю его silent - как раз как в случае с сохранением из детали. И this.set("Operation", Terrasoft.ConfigurationEnums.CardOperation.EDIT) тоже происходит в методе onSaved до открытия кастомной страницы (про этот "режим" вы говорите? или про silent save все же ?)

В более старых версиях помнится при добавлении новой записи был хеш вида CardModuleV2/OrderPageV2/add/recordId Почему от этого отказались - неясно.

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

this.isAddMode() 

там аккурат считывается значение этого атрибута.

PS:
зачастую просто надо предотвратить поведение при котором новая карточка закрывается при сейве, этот кейс решается именно так.

Илья, режим хранится как раз в атрибуте Operation. То есть он сменяется на EDIT до того как я открываю кастомную страницу. Проблема состоит именно в том, что при нажатии Закрыть на кастомной странице идет запрос BackHistoryState, а там - хеш раздела. Вот и идет вылет в раздел.

В общем, пока проблему обходим следующим путем:

1) На странице заказа перенесли вызов метода, отвечающего за открытие кастомной страницы подборщика, из onSaved в onSilentSaved, так как он вызывается до смены режима в атрибуте Operation
2) сам режим передаем в массиве defaultValues на кастомную страницу. Код выглядит теперь так

openProductSelector: function() {
	var orderId = this.get("PrimaryColumnValue") || this.get("Id");
	var operation = this.get("Operation");
 
	var defaultValues = [
			{
				name: "PrimaryColumnValue",
				value: orderId
			}, 
			{
				name: "UseSeparatedPageHeader",
				value: true
			},
			{
				name: "Operation",
				value: operation
			} 							
		];
 
	stateObj = {
					isSeparateMode: true,
					schemaName: "SelectProductInOrderPage",
					moduleId: "CardModuleV2_SelectProductInOrderPage",
					valuePairs: defaultValues,
					operation: "open",
					isInChain: false
				};
	requestUrl = "CardModuleV2/SelectProductInOrderPage/";
 
	this.sandbox.publish("PushHistoryState", {
		hash: requestUrl,
		stateObj: stateObj
	});
},	
 
onProductSelectionButtonClick: function() {
	this.set("OpenselectProductPage", true);
	this.save({isSilent: true});
},
 
 
onSilentSaved: function() {
	if(this.get("OpenselectProductPage")) {
		this.openProductSelector();
	this.set("OpenselectProductPage", false);
	} else {
		this.callParent(arguments);
	}
}  

3) на кастомной странице создали кнопку по виду идентичную кнопке Закрыть. Видимость этой кастомной кнопки прибиндили к isNewMode, а кнопки Закрыть к противоположному к isNewMode значению.
4) Метод обработчик нажатия на кастомную кнопку открывает наш заказа в режиме редактирования.

onBacktToOrderButtonClick: function() {
		var orderId = this.get("PrimaryColumnValue") || this.get("Id");
		var defaultValues = [
				{
					name: "PrimaryColumnValue",
					value: orderId
				}					
		];
 
		stateObj = {
						isSeparateMode: true,
						schemaName: "OrderPageV2",
						moduleId: "CardModuleV2_" + orderId + "_OrderPageV2",
						valuePairs: defaultValues,
						operation: "edit",
						isInChain: false
					};
		requestUrl = "CardModuleV2/OrderPageV2/edit/" + orderId;
 
		this.sandbox.publish("PushHistoryState", {
			hash: requestUrl,
			stateObj: stateObj
		});				
},

Но это решение все равно несколько "корявое". Так как при создании нового заказа: карточка заказа. Открыть подборщик => Подборщик. Закрыть => Карточка Заказа. Закрыть => попдаем обратно в подборщик вместо раздела.

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

Когда пользователь кликает по гиперссылкам в окне приложения страницы по которым он перемещаются образуют очередь (стек LIFO), типовые действия "Закрыть" / "Сохранить" и т.д. приводят к тому что пользователь "возвращается на карточку", зачастую работая с другими карточками пользователь инициирует БП или иначе изменяет данные, которые ранее были загружены в модели карточек к которым предстоит "вернуться", но когда пользователь "возвращается на них" то данные там не актуализированы.
И это представляет прям насущную проблему.
Её не сложно решить самостоятельно, имея какой-то способ определения факта события "пользователь вернулся на карточку".
Стоит признаться, "ковырялся" я довольно много... но пока что "зацепиться" ни за что не удалось.
Но мне кажется что, способ всё такие есть.

Есть ли у коллективного разума какие-то идеи, знания на этот счет ?

Нравится

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

Сам спросил, сам отвечу
за это отвечает BROADCAST сообщение BackHistoryState
на него есть всего один подписчик в ConfigurationBootstrap.js
его обрабатывает метод onBackHistoryState
так что можно "расширять" его при необходимости.

PS: по факту этот метод не делает ничего кроме вызова

router.back();

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

Ладно, вы справились быстрее, поздравляю :smile:

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

Добрый день!
Возникла проблема при работе с SVN.
Не удается обновить или зафиксировать пакеты.
В конфигурации ошибка выглядит так: "The XML response contains invalid XML"

Лог ошибки:
2017-07-21 13:40:39,965 [86] ERROR NT AUTHORITY\SYSTEM Svn ThrowException - The XML response contains invalid XML
RootCause: The XML response contains invalid XML
SvnErrorCode: SVN_ERR_XML_MALFORMED
SvnErrorCategory: 26
Workspace Number: 0
Workspace Name: Default

В чем может быть проблема?

Нравится

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

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

Похоже на внутреннюю ошибку svn, начать можно с проверки url svn сервера, также можно попробовать выкачать репозиторий какой-то сторонней утилитой (например tortoise svn) и попробовать зафиксировать какие-то изменения.

Также можно открыть рабочую копию в файловой системе, если это on-site, и попробовать выполнить svn cleanup, но осторожно, там есть опция по отмене изменений, она должна быть выключена

"Мотков Илья" написал:

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

Похоже на внутреннюю ошибку svn, начать можно с проверки url svn сервера, также можно попробовать выкачать репозиторий какой-то сторонней утилитой (например tortoise svn) и попробовать зафиксировать какие-то изменения.

Также можно открыть рабочую копию в файловой системе, если это on-site, и попробовать выполнить svn cleanup, но осторожно, там есть опция по отмене изменений, она должна быть выключена


Добрый день, дело в том, что подобные on-site приложения уже ранее были развернуты и на них не возникало таких проблем, так как производилась, так сказать, установка с 0 (подключение svn, установка пакетов из svn и так далее). Проблема возникает только в тот момент, когда пытаемся развернуть новое приложение из готового бэкапа старого. Т.е. получается что конфигурации +- между собой схожи, так что кажется навряд-ли url svn сервера как то менялся.

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

Добрый день!
Столкнулся с проблемой вывода в дашборде продаж, в которых ВСЕ заказы находятся в состоянии Отменен. В моем случае выводятся продажи, в которых есть заказы в состоянии Отменен.

Нравится

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

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

В построителе выборки Вы можете использовать does not exists (или не существует) фильтр, в котором перечислить все остальные состояния отличные от 'Отменен'.
Более подробно о построении таких фильтров (пункт "Установка агрегирующего фильтра" - вместо количества нужно указать опцию не существует):
https://academy.terrasoft.ru/documents/sales-team/7-10/rasshirennyy-fil…

P.S. прикрепила скриншот для наглядности

Алла, спасибо за решение)

Добавьте еще условие, что заказы существуют. И при это не существуют заказы, в которых состояние отличное от "Отменен"

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

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

На открытой CTI панели звонков есть функция поиска по контактам (см. скриншот).
Там есть кнопочка с телефонной трубкой. Однако кликнуть по ней, чтобы позвонить, не получается.

Можно ли где-нибудь добавить обработку на этот клик, в какой схеме определён этот блок?
Или убрать кнопку, как вариант.

Нравится

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

обработчик - callPhoneNumber
находится в CtiPanelModelUtilities

добавление строки-элемента в CTIPanel

{
	"operation": "insert",
	"parentName": "ctiPanelMainContainer",
	"index": 4,
	"propertyName": "items",
	"name": "PhoneNumber",
............................................и т.д.
},

Данила, спасибо!

Но есть ещё один момент. Это звонок по кнопке 1 (на прикреплённой картинке).
Можно ли вызвать звонок по кнопке 2?

Также есть аналогичная кнопка в ленте звонков.

там обработчик onNumberClick,
из, скорее всего, CommunicationHistoryItem

Данила,

CommunicationHistoryItem - это для истории звонков. Туда добавил обработчик кликов.

Есть ещё результаты поиска, они на первом скрине были..

Пока нашёл в SubscriberSearchResultItem вот такое:

{
					"operation": "insert",
					"name": "CommunicationItemsListContainer",
					"parentName": "SubscriberSearchResultItemContainer",
					"propertyName": "items",
					"values": {
						"id": "CommunicationItemsListContainer",
						"itemType": Terrasoft.ViewItemType.GRID,
						"markerValue": "CommunicationItemsListContainer",
						"selectors": {"wrapEl": "#CommunicationItemsListContainer"},
						"idProperty": "Id",
						"collection": {"bindTo": "SubscriberCommunications"},
						"onGetItemConfig": {"bindTo": "getCommunicationPanelViewConfig"},
						"classes": {"wrapClassName": ["communications-control-group"]},
						"generator": "CtiContainerListGenerator.generatePartial"
					}
				}

Похоже, что кнопка где-то рядом.. пока не нахожу что-то.

Нашёл - схема SubscriberCommunicationItem.

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

BPM 7.10
При создании нового элемента, при выборе определенного значения категории (например - К1), изменить уровень доступа к полям этого элемента. Т.е. при открытии поле под замком, после выбора категории и установки параметра в значение "К1" - замок убрать.

Предполагаю, выполняться это должно на клиенте, т.е. использование JS.

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

Нравится

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

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

Для этого можно использовать бизнес-правила. Подробнее по ссылке:
https://academy.terrasoft.ru/documents/sales-enterprise/7-10/nastroyka-…

"Терещенко Алексей" написал:Подскажите есть ли библиотека с примерами, которые можно было бы самостоятельно проанализировать для выполнения собственного функционала?

ну кое что есть на академии в специальном разделе
а так, основной источник примеров - это исходники конфигурации, вот тут о том как их выгрузить

"Севостьянов Илья Сергеевич" написал:ну кое что есть на академии в специальном разделе

Спасибо. Реализовал с помощью бизнес-правил.

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

Хочу поделиться интересной 'фичей', обнаруженной при настройке графиков в дешбордах.

Если у Вас в графике есть несколько серий и для первой серии установить тип графика 'Bar' (скрин 1), а для другой 'Column' (скрин 2) (возможно, что в русскоязычной локализации они называются по-другому), то в итоге Вы получите эффект 'вложения' одной серии в другую (для понимания этого эффекта лучше посмотреть прикрепленный скриншот график).

P.S. Не исключаю, что такой эффект после внесения изменений и исправлений в графики после очередного обновления на новую версию может пропасть, так как отображаться в итоге должно нечто другое, соответствующее указанному типу графика, но пока такой эффект присутствует вы можете использовать его в настройке ваших дешбордов, тем более, что нашим пользователям он очень понравился :wink:

Сейчас у нас версия 7.10.2.

Нравится

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

Это именно что фича а не баг, и тянется она давно, и не планирует исчезать :smile:

Максим,

хорошо, если так.

Мы этому будем только рады!

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

В статье Добавление автонумерации к полю страницы описан пример из которого не совсем понятна следующая строка UserTask1.EntitySchema = Entity.Schema;.
"Установка схемы для генерации номера." - т.е. логично предположить, что Entity.Schema - схема автонумерации? Как-то не понятно...
...тогда вопрос: какие существуют еще схемы?
А если возникнет необходимость в одном разделе, в одной таблице еще одни номер сгенерировать (т.е. в двух разных полях разные номера) тогда как?

Нравится

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

"Терещенко Алексей" написал:.е. логично предположить, что Entity.Schema - схема автонумерации? Как-то не понятно...

Ноуп.
UserTask1 - таск генерации номера (пользовательское действие вроде называется, которое вы тащите с левой панели).
.EntitySchema - входящий параметр этого генератора

Entity - экземпляр класса Entity под текущий объект
.Schema - поле со схемой объекта (таблицы)

"Варфоломеев Данила" написал:UserTask1 - таск генерации номера
- нет. генерация номера в данном ЮзерТаск1 - это значение, выбранное в поле "Действие". Как таково сам по себе ЮзерТаск1 - не производит никакой генерации.

На самом деле если Вам необходим просто итерируемый номер, логика описанная в статье - избыточна.
Он имеет смысл к реализации когда номер строится с участием "маски".
Самый простой способ - это создать свою системную переменную под каждую нумеруемую сущность.
И в своей реализации получать значение и итерировать его самостоятельно. (Или на бэкенде в БП или на фронте в JS)
на фронте

//получить значение системной переменной
//https://academy.terrasoft.ru/jscoresdk/#!/api/Terrasoft.core.SysSettings-method-querySysSettings
Terrasoft.SysSettings.querySysSettings(SysSettingNamesArray, callback, scope)
//установить значение системной переменной
//https://academy.terrasoft.ru/jscoresdk/#!/api/Terrasoft.core.SysSettings-method-updateSysSettingsValue
Terrasoft.SysSettings.updateSysSettingsValue(configurationObject, callback, scope)
Показать все комментарии

Доброго времени суток. Где можно взять установщик BPM Online? Разработка on-cloud недостаточно хороша, хотелось бы вести разработку со своей машины.

Нравится

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

Добрый день,

Для предоставления дистрибутива у Вас на CustomerId должны быть лицензии.
Подскажите, пожалуйста, Ваш CustomerId, а также название Вашей компании.

С уважением,
Наталия

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

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

Нравится

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

Первое что напрашивается это конечно же настройка прав доступа:
https://www.youtube.com/watch?v=x5C6VcOhKj4
Колонки не будут серыми и недоступными на изменение, но запись сохранить у пользователя не получится, будет соответствующее сообщение об отсутствии прав.

Другой способ же, бизнес правила по условиям на "только чтение":
https://academy.terrasoft.ru/documents/technic-sdk/7-8/pravilo-bindpara…
Работы тут больше, т.к. на каждое поле прийдется писать свое правило.

"Максим Шевченко" написал:Работы тут больше, т.к. на каждое поле прийдется писать свое правило.

А можно как-то скриптом перебрать все поля страницы и всем поставить "только чтение", как это делалось в 3.х?

Добрый день!
Можно сделать с помощью CSS. Т.е. при открытии карточки вы устанавливаете стиль.
К примеру, чтобы все читалось, но не редактировалось (правда и не кликалось), то можно добавить стиль в основной контейнер карточки: pointer-events: none;
Если же вам нужно чтобы только нужные элементы, то подход тот же, но CSS другой.
Пример:
div input,a,span,div[id*='Container_Control'],div[class='base-edit-clear-icon'] {
pointer-events: none;
}
Можно добавить opacity для визуализации :)

Просто другие варианты трудозатратны, а это простой способ

"Владимир Соколов" написал:А можно как-то скриптом перебрать все поля страницы и всем поставить "только чтение", как это делалось в 3.х?

Ну при помощи Ext.JS можно проделать вот такой "хак"

Ext.ComponentMgr.all.each(function(c){
	var cmp = Ext.ComponentMgr.all.map[c];
	if(cmp.className){
		if(cmp.className.indexOf("Edit") !== -1){
			if(cmp.setEnabled){
				cmp.setEnabled(false)
			}
                }
	}
})

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

Есть несколько НО:
1) ререндер карточки - это состояние сбросит.
(в основном это создает проблемы, при переходе из карточки в карточку по Chain, что кстати было бы возможно предусмотреть и исправить, если бы на мой вопрос вот здесь, кто ни будь нашел/дал ответ)
2) это не касается каких либо элементов управления кнопок, пунктов меню и т.д. только поля.

"Владимир Соколов" написал:
Максим Шевченко пишет:

Работы тут больше, т.к. на каждое поле прийдется писать свое правило.

А можно как-то скриптом перебрать все поля страницы и всем поставить "только чтение", как это делалось в 3.х?

Собрал замещающий модуль для BasePageV2. Перебирает все поля и проставляет атрибут Enabled = False. Управляется всё дефолтным параметром "CardState" который передаётся в схему.

define("BasePageV2", ["ConfigurationEnums"], function (enums) {
return {
messages: {

},
methods: {
disableControls: function (item, callback) {
if (item.item) {
this.disableControls(item.item)
} else
if (item.className === "Terrasoft.Container" || item.className === "Terrasoft.GridLayout" || item.className === "Terrasoft.ControlGroup") {
for (item of item.items) {
this.disableControls(item)
}
} else
if (this.isEditClassname(item.className)) {
item.enabled = false;
}
else
console.log(item.className);

if (callback)
callback.call(this);
},
isEditClassname: function (name) {
return this.getEditControlsClassNames().indexOf(name) != -1;
},
getEditControlsClassNames: function () {
var EditControlsClassNames = ["Terrasoft.Label","Terrasoft.DateEdit", "Terrasoft.LookupEdit", "Terrasoft.TextEdit",
"Terrasoft.ListView", "Terrasoft.RadioButton", "Terrasoft.TimeEdit", "Terrasoft.FloatEdit",
"Terrasoft.CheckBoxEdit", "Terrasoft.ComboBoxEdit", "Terrasoft.InlineTextEdit", "Terrasoft.ImageEdit", "Terrasoft.IntegerEdit", "Terrasoft.MemoEdit"]
return EditControlsClassNames;
},
getCardState: function () {
return this.getDefaultValueByName("CardState");
},
init: function () {
var cardState = this.getCardState();
if (cardState && cardState === enums.CardState.View) {
var parentMethod = this.getParentMethod();
var arg = arguments;
this.disableControls(arguments[1].viewConfig[0], function () {
parentMethod.apply(this, arg);
});
}
else {
this.callParent(arguments);
}
}
},
diff: /**SCHEMA_DIFF*/[

]/**SCHEMA_DIFF*/
};
});

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