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

Версия 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 

Статья тут.

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

Добрый день.

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

  1. Настроил процесс в соответствии с инструкцией.
  2. Написал консольное приложение для создания записей в несколько потоков в соответствии с инструкцией.

При первом же тесте по созданию записей в 20 потоков, по 1 записи в каждом потоке, получил следующие результаты:
Дубли2

Собственно вопросы:
Есть ли какая то возможность гарантированно генерировать уникальный номер?
Есть ли возможность модифицировать класс GenerateSequenseNumberUserTask?

Нравится

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

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

Альтернативный вариант - генерировать номер по факту создания записи триггером в БД.

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

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

Альтернативный вариант - генерировать номер по факту создания записи триггером в БД.


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

Например шаблон названия/кода: <Тип_записи>/<Категория_записи>/<Год_создания>_<Уникальный_порядковый_номер>

И есть ли возможность модифицировать класс GenerateSequenseNumberUserTask, который отвечает за генерацию номера?

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

Можно сделать следующее:
1) В конфигурации выгрузить GenerateSequenseNumberUserTask.md (выделите схему и выберите действие "Экспорт в файл".
2) Открыть выгруженный файл и подменить значения параметров:

  • UID
  • NAME
  • CAPTION

3) Загрузить полученный файл в конфигурацию (действие "Импорт файла")
4) Внести в загруженный файл требуемые изменения
5) Опубликовать изменения
6) Использовать в действии процесса на объекте созданное (импортированное вами действие)

P.S. Все еще не вижу проблемы в создании триггера.

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

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

Возникла такая проблема: на странице реестра записей Юр. Лица реализовали действие, по нажатию на которое появляется окно выбора справочного значения, и при выборе нужного значения, оно меняется у всех Юр. Лиц, отфильтрованных в реестре. Теперь надо добавить окно подтверждения для пользователя. Я вижу решение двумя способами, но не знаю как реализовать:
1) Добавить дополнительное pop up окно с вопросом-подтверждением действия и выбором из двух значений, либо подтвердить, либо не подтвердить.
Но, с созданием таких окон проблемы и код получится большим на мой взгляд.
Если есть похожие реализованные кейсы, поделитесь пожалуйста :)
2) Добавить маленький процесс с 1-2 двумя элементами: Вопрос пользователю. И если пользователь выбирает "Да", то запускать код, который описан в начале.
Этот вариант предпочтительнее, но я не знаю как передать значение/параметр из процесса в код, описанный в начале.
Если кто сможет подсказать как передать значение из процесса, помогите плиз :)

С уважением,
Дмитрий

Нравится

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

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

Алгоритм решения задачи:
1. В рамках процесса сгенерировать сообщение по WebSocket (элемент ScriptTask).
2. На целевой карточке подписаться на сообщение.
3. В обработчике реализовать интересующую логику.
Пункт 1 и 2 рассмотрены тут: http://www.community.terrasoft.ru/forum/topic/11784

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

Коллеги, добрый день.
После обновления версии приложения до 7.9.1.3284 пропали все настроенные колонки в деталях, сбились колонки реестра в разделах.
Вопрос первый. Есть ли возможность в системе восстановить все так, как было?
Вопрос второй. Если восстанавливать руками, то возникает другая сложность. При желании настроить колонки детали "Доступ к операции" в "Права доступа на операции" -> "Экспорт реестра" нет строчки "Настроить колонки".
Что делать в таком случае?

Нравится

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

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

Настройки колонок раздела и деталей хранятся в объекте (таблице) SysProfileData. Если у вас решение on-site, то вы можете самостоятельно перенести настройки. Если решение on-demand - обратитесь в службу поддержки.

Сценарии обновления предполагают перенос настроек. Возможно при обновлении была какая-то ошибка.

Алексей, спасибо за информацию!

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

Версия
7.9.1.3284
Нужно добавить в БП звонок-элемент чтобы его привязать к активностям и другим объектам.

Нравится

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

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

Опишите подробней ожидаемый результат выполнения такого элемента и какие бизнес-задачи вы хотите решить.
Запись можно добавить с помощью элемента [Добавить данные], указать целевой объект и заполнить связи с другими объектами.

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

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

Вы можете настроить процесс:
1. Стартовый сигнал по изменению записи в звонке, где Активность заполнена.
2. Читать данные в активности, где Id = Пункт 1. Активность.
3. Раздать права доступа на активность, где Id = Пункт 2. Id
4. Открыть страницу редактирования активности, где Id = Пункт 2. Id

Хорошо, это сделаю, но как настроить видимость кнопок звонка и эмейла в миникарточке активности, они создаются динамически. (две кнопки ля контакта и две для контрагента)

Добрый день!

Не могли бы Вы прикрепить скриншот Вашей миникарточки и код создания данных кнопок?


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

Здравствуйте, Виталий!

Логика данной миникарточки находится в UIv2.ActivityMiniPage. Кнопки добавляются при ее создании(методы init и onEntityInitialized). Логика отображения кнопок находится в UIv2.MiniPageEntityConnectionsUtils и NUI.EmailExtendedMenu и работает именно так как Вы описали - при создании миникарточки формируется EntitySchemaQuery запрос в базу данных, и если у данного контака(контрагента) заполнена колонка телефон(e-mail) кнопка будет добавлена. Если таких данных нет - не будет и кнопки.

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

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

Нравится

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

Здравствуйте, Дмитрий!

Так как данная функциональность реализована на уровне ядра, доступными пользовательскими средствами этого сделать нельзя.

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

"Зверев Александр" написал:можно сделать новое пользовательское меню средствами разработки конфигурации

Это интересно. А где-нибудь примеры кода есть?

К сожалению, готовых примеров нет.
Меню с пунктами создаётся в дизайнере карточки как невизуальный компонент и крепится к полю ввода.
menu
tree

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

7.9.0.1228 (коробка SalesEterprise)

Только что развернутая из дистрибутива версия приложения.
Подключили хранилище, начали устанавливать свои пакеты.
И имеем вот такое предупреждение (см.вложение),
при том, что наших пакетов естественно в конфигурации нет, и они никак не могли они быть ранее установлены и например удалены.

Собственно вопрос, коллеги, в чем может быть причина такой сообщения?

Нравится

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

Здравствуйте, Михаил!

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

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