Агенты-->Контакты. При нажатии на контакт в контекстном меню правой кнопкой мышки открывается окно с функционалом(отправить е-mail, позвонить, объединить записи ........).
При наведении на отправить е-mail появляется окно(ответственный, создал, изменил). В это открытое окно надо добавить поле контакт. То есть должно появиться окно вида: отправить е-mail --> (контакт, ответственный, создал, изменил). Подскажите пожалуйста как найти функционал где реализован этот выпадающий список. Спасибо

Нравится

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

Он заполняется в скрипте CreateEmailCustomContextMenu_ScriptTask в БП страницы BaseGridPage.
Там перебираются все колонки объекта и для тех, что ссылаются на справочники «Контакт» и «Сотрудник» вызаывается функция EmailContextMenuItem, создающая пункт меню. Теоретически, можно попробовать доработать, чтобы в этот список попадала и колонка «Id» раздела.

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

Он заполняется в скрипте CreateEmailCustomContextMenu_ScriptTask в БП страницы BaseGridPage.

Там перебираются все колонки объекта и для тех, что ссылаются на справочники «Контакт» и «Сотрудник» вызаывается функция EmailContextMenuItem, создающая пункт меню. Теоретически, можно попробовать доработать, чтобы в этот список попадала и колонка «Id» раздела.


Извини может глупый вопрос, но возможно ты знаешь где я допустил ошибку или как можно решить эту проблему. Весь функционал работает для контакта. Но когда сделал для контрагента, окно тоже появляется но при нажатии на функционал(отправить на Email) в открывшем окне не подставляется Email контрагента в поле Кому. Все изменения в скриптах которые вносил отмечены /*add*/... Спасибо большое.
CreateEmailCustomContextMenu_ScriptTask в пакете BaseGridPage

var contactSchemaId = new Guid("16be3651-8fe2-4159-8dd0-a803d4683dd3");
var employeeSchemaId = new Guid("fb1c2bed-91d4-4b06-a28c-621a3d187008");
/* +Add IdAccount --   var accountSchemaId = new Guid("25d7c1ab-1de0-4501-b402-02e0e5a72d6e");

    +Add -- Реализована логика проверки наявности заполненного поля в объектах контакта и контрагента. Если поле заполнено то отобразить дополнительный функционал.
var ContactEmail = "";
var AccountEmail = "";

ContactEmail = Terrasoft.Configuration.CommonUtilities.GetEntityTypedColumnValue(UserConnection, "Contact", "Email", Page.DataSource.ActiveRowPrimaryColumnValue);

if (email != "" && Page.DataSource.Schema.UId == contactSchemaId) {
	var menuItem = EmailContextMenuItem(Page.DataSource.Schema.Caption, GetSchemaTag("Contact", Page.DataSource.ActiveRowPrimaryColumnValue));
	(Page.TreeGrid.Menu[0] as MenuItemBase).Menu.Add(menuItem);
	(Page.AspPage as Terrasoft.UI.WebControls.Page).RegisterClientSpecialInitScript(string.Format("{0} = {{}};{0}.setImage = Ext.emptyFn;", menuItem.ClientID));
	(Page.TreeGrid.Menu[0] as MenuItemBase).Menu.AddCaptionItem(menuItem);
}

AccountEmail = Terrasoft.Configuration.CommonUtilities.GetEntityTypedColumnValue(UserConnection, "Account", "InvoicesEmail", Page.DataSource.ActiveRowPrimaryColumnValue);

if (AccountEmail != "" && Page.DataSource.Schema.UId == accountSchemaId) {
	var menuItem = EmailContextMenuItem(Page.DataSource.Schema.Caption, GetSchemaTag("Account", Page.DataSource.ActiveRowPrimaryColumnValue));
	(Page.TreeGrid.Menu[0] as MenuItemBase).Menu.Add(menuItem);
	(Page.AspPage as Terrasoft.UI.WebControls.Page).RegisterClientSpecialInitScript(string.Format("{0} = {{}};{0}.setImage = Ext.emptyFn;", menuItem.ClientID));
	(Page.TreeGrid.Menu[0] as MenuItemBase).Menu.AddCaptionItem(menuItem);
} 
 --add 
*/

ProcessEmailContextMenuClick_ScriptTaskExecute в пакете BaseGridPage

var extraParams = context.ThrowEventArgs as Dictionary;
string tag = extraParams["tag"].ToString();
OpenEmailEditPage_BaseGridPage_UserTask.OpenerInstanceId = Page.Process.InstanceUId;
OpenEmailEditPage_BaseGridPage_UserTask.PageUId = new Guid("DCDDA065-321B-4560-AACB-05F6CC72CD80");
Dictionary  parameters = new Dictionary () {
	{"ContactId", ReadIdFromTag(tag, "ContactId").ToString()},
	{"TemplateId", ReadIdFromTag(tag, "TemplateId").ToString()},
/* +add 
        {"AccountId", ReadIdFromTag(tag, "AccountId").ToString()},
*/ -add
	{"customClosedEvent", "EmailEditPageClosed"}
};
OpenEmailEditPage_BaseGridPage_UserTask.PageParameters = parameters;
return true;

Александр, во втором фрагменте Вы передаёте дополнительный параметр AccountId в карточку нового письма, которая должна открыться. Чтобы он обрабатывался, нужно в БП той страницы внести дополнительную логику, аналогично тому, как сделано для ContactId. См. в БП страницы EmailEditPage скрипт EnableSendButton, а конкретно строки:

var parameterContactId = GetIdFromParameter("ContactId");
	if (!parameterContactId.Equals(Guid.Empty)) {
		dataSource.ActiveRow.SetColumnValue("Recepient", GetRecipientByContact(parameterContactId));
	}

Для функции GetRecipientByContact (в дереве функций этой же страницы), которая получает адрес по Id контакта, тоже придётся написать аналог для схемы контрагента.

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

Здравствуйте!
Начал изучать BPMOnline (7.8 тестирую). Подскажите, как сделать, чтобы при создании Продаж, Контрагентов, Контактов и т.п. по умолчанию устанавливались нужные права доступа.
К примеру для Контрагентов, чтобы только тот, кто создает нового Контрагента имел право на чтение, изменение. (Сейчас устанавливаются права по умолчанию для автора и группы Все сотрудники).

Нравится

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

Добрый день!!!

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

если появятся дополнительно вопросы пишите. спасибо!!!

Добрый день!

Права доступа не менялись по отношению к предыдущим версиям.
Рекомендую перед началом настройки прав ознакомиться с видео-уроком по правам доступа:

https://www.youtube.com/watch?v=x5C6VcOhKj4&feature=youtu.be&list=PLDp-…

В Вашем же кейсе, необходимо убрать настройку "Кто создает = Все сотрудники" = "Кому дано право = Все сотрудники" из администрирования по записям на объект "Контрагенты".

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

Добрый день.

Проблема с обновлением грида детали после добавления элемента в деталь. Элемент не появляется в гриде сразу после выбора.

1. Выбор элементов в детали реализован с помощью LookupUtilities:

        var lookupConfig = {
                entitySchemaName: "BankingService",
                columnName: "Name",
                columns: ["ClientType"],
                multiSelect: true,
                filters: filters
        };
           
        LookupUtilities.ThrowOpenLookupMessage(
            sandbox,
            lookupConfig,
            this.addBankingServiceItemsCallback,
            this,
            this.getCardModuleSandboxId()
        );

2. Собственно callback-функция для обработки выбора пользователя:

                this.methods.addBankingServiceItemsCallback = function(args) {
                        if (!args || args.selectedRows.getCount() === 0) {
                                return;
                        }
                       
                        var selectedIds = args.selectedRows.getKeys();
                        var synchronizedRule = this.filterValue;
                        var batchQuery = Ext.create('Terrasoft.BatchQuery');
                        Terrasoft.each(selectedIds, function(item) {
                                var insert = Ext.create('Terrasoft.InsertQuery', {
                                        rootSchemaName: this.entitySchema.name
                                });
                                var newGuid = Terrasoft.generateGUID();
                                insert.setParameterValue(
                                        'Id',
                                        newGuid,
                                        Terrasoft.DataValueType.GUID
                                );
                                insert.setParameterValue(
                                        'BankingService',
                                        item,
                                        Terrasoft.DataValueType.GUID
                                );
                                insert.setParameterValue(
                                        'SynchronizedRule',
                                        synchronizedRule,
                                        Terrasoft.DataValueType.GUID
                                );
                                batchQuery.add(insert);
                        }, this);
                        batchQuery.execute();
                        sandbox.publish('DetailChanged', {detailName: this.entitySchema.name}, [this.getSenderSandboxId()]);
                };

3. Обработчик события DetailChanged на странице редактирования объекта с деталью:

                this.methods.detailChangedSubscriber = function(args) {
                        viewModel.reloadDetail(args.detailName + 'Detail');
                };

Однако, после нажатия кнопки "Выбрать", выбранные записи в гриде детали не отображаются. Если нажать "Сохранить" на странице редактирования объекта и потом открыть заново этот объект для редактирования, то в детали выбранные записи видны.

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

Заранее благодарен за помощь!

Нравится

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

Добрый день Артем!!!

уточните пожалуйста версию и конфигурацию BPMOnline. Спасибо!!!

"Власов Михаил Викторович" написал:

Добрый день Артем!!!

уточните пожалуйста версию и конфигурацию BPMOnline. Спасибо!!!

Михаил, версия 7.2; конфигурация вроде "lending"

Здравствуйте, я не воссоздавал на тестовом примере batchQuery, это не суть вопроса, сразу менял данные детали в базе данных, через sql management studio. Самое главное здесь в вашем вопросе, это вызов «viewModel.reloadDetail(args.detailName + 'Detail');»

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

Во-вторых, почему viewModel? Данный метод же есть прямо в главном скоупе страницы. Я закешировал для теста скоуп страницы в инит методе:

structure.userCode = function() {
   this.methods.init = function() {
      document.scp = this;
   };
};

И вот видно наш метод для обновления детали:

Во вторых, имя, передаваемое как аргумент должно соответствовать именно «name» свойству детали, а не «schemaName». Вот, к примеру, деталь опыта работы контакта:

И вот такой её вызов, отлично обновляет содержимое грида:

document.scp.reloadDetail("contactCareer");

где «document.scp» по сути this скоуп страницы контакта.

Вывод: Отладьте метод, проверьте имена.

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

Здравствуйте. У нас система bpm online sales commerce Версия 7.7.0.2875

Мне нужно както быстро менять ответственного по активности и ответственного по контакту для нескольких контактов. Если делать через сиистему - то можна только по одному. Сначала в активности менять ответственного - сохранять а потом в контакте и сохранять. Это очень долго, если нужно сразу переставить 50-100 задач за день с одного менеджера на другого и при этом поменять ответственного в контакте.

Если какой-то быстрый метод для такой задачи? Спасибо!

Нравится

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

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

Для решения этой задачи Вы можете создать бизнес процесс, состоящий из трех элементов:
1) Начальный элемент
2) Изменить данные по объекту "Активность".
В фильтрации прописать условие, которое выберет записи, где нужно изменить ответственного.
В значение поле "Ответственный" необходимо установить нового ответственного
3) Конец процесса

С контактами - аналогично. Единственное отличие - во втором пункте объектом необходимо выбрать "Контакт".

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

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

"Власов Михаил Викторович" написал:Чтобы в системе был универсальный настраеваемый инструмент, позволяющий в любой сущности конфигурации выполнять массовое замену значений

Особенно при чистке справочников. А то навводят городов, а потом их не почистить никак

"Владимир Соколов" написал:Особенно при чистке справочников. А то навводят городов, а потом их не почистить никак

Для этого гораздо лучше было бы вернуть с того света универсальный поиск дублей (3.х), который эту проблему позволял решать.

"Александр Кудряшов" написал:Для этого гораздо лучше было бы вернуть с того света универсальный поиск дублей (3.х), который эту проблему позволял решать.

Тоже идею надо публиковать. Глядишь, сделают одновременно с выпуском беспилотных автомобилей Google на улицы в 2018 году :)

Беспилотники Google врятли успеют появиться, япония обганяет в данном вопросе Google мобили. Их мобили уже по улицам городов, не всех но уже ездят. Народ читал, сильно не довольны, так как Аварий по вине беспилотного автомобиля, сейчас в японии очень большие. А у Google они еще в рамках их тестовых площадок ездят.

Здравствуйте!
А как мне выбрать фильтр чтобы вибырвльсь все активности - задачи, без Email? Как мне отбросить эти Емейлы?

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

В элементе "Изменить данные" по объекту "Активность" добавить условие "Тип" не равно E-mail.

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

Добрый день. Работаю с BPMonline 7.3. Необходимо реализовать экспорт в Excel отчета, который на данный момент вызывается с указанием фильтров в разделе "Аналитика" модуля Документ. Как это можно сделать?

Нравится

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

Добрый день Наталия!!!

по умолчанию в версии 7.3 как и выше создавать Отчеты в Эксель формате нет возможности. Для того чтобы создать Отчет в эксель формате я бы советовал использовать, загрузив во Внешние сборки, стороннюю DLL позволяющую формировать отчеты в Эксель формате. Я к примеру использую DLL от компании Syncfusion - "Syncfusion.XlsIO.Base.dll"

Или у вас Наталья в другом проблема, и я вас неправильно понял, прочитав ваше сообщение. Поясните пожалуйста побее детально, задачу что требуется решить. Спасибо!!!

Добрый день, Михаил!

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

Клиент хотел бы иметь такой же отчет в виде XLS файла.

Добрый день Наталия!!!

как я и писал выше, для решения вашей задачи вам лучше использовать стороннюю DLL позволяющую создавать Отчеты в эксель формате. Еще раз повторюсь стандартными инструментами BPMOnline этого не умеет делать, только PDF, Word

Михаил, спасибо за ответ. Т.е. я так понимаю, задачу, стоящую передо мной, можно технически реализовать?
Если можно - дайте ссылки на информацию, как загружать стороннюю DLL в проект, как ее подключать.
Заранее спасибо!
И как данная реализация выглядит у Вас? Т.е. можно использовать те же фильтры? Если можно - примерный план реализации.
Буду очень признательна!

Возможно, с помощью Power Pivot через ODATA вытащить данные из bpm, и уже в Excel построить отчет?

"Владимир Соколов" написал:Возможно, с помощью Power Pivot через ODATA вытащить данные из bpm, и уже в Excel построить отчет?

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

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

"Власов Михаил Викторович" написал:
Но думаю клиенту нужно чтобы прямо из программы формировался отчет.

Именно так!

Поднимаю вопрос....

Здравствуйте, Наталия!
Для загрузки внешних библиотек Вам необходимо перейти в конфигурацию. В конфигурации есть вкладка "Внешние сборки". Именно туда необходимо загружать *.dll файлы.

Пример формирования отчета в формате *.docx, *.pdf Вы можете посмотреть в схеме ReportHelper.

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

Добрый день, коллеги! Подскажите, пожалуйста, с чем может быть связан периодический простой сервера и клиента при работе в практически любом разделе системы, в том числе и стандартных (Администрирование), как под админом так и под пользователем, при этом помогает только перезагрузка сервера CRM. На трэйсе видно, что сервер никаких запросов не обрабатывает, в то время как клиент, так же, никаких видимых в проц мониторе действий, не выполняет.

Нравится

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

А "простой" то в чем выражается?

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

Добрый день Антон!!!

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

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

Добрый день Антон!!!

если данная проблема наблюдается сразу на нескольких компьютерах, то есть у меня подозрение, что это уже железо сервера начинает страдать или уже страдает. Я бы проверил уже Память на предмет ошибок и диски на предмет BAD секторов и скорости чтения записи. Есть множества разных утилит внешних. Завтра могу у хорошего системного администратора уточнить название данных программных продуктов. Хотя могу ошибаться, так как логически если рассуждать, если начало бы сыпаться железо на сервере, то это было бы явно заметно.

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

Здравствуйте, Антон!

Уточните, пожалуйста, полное название используемой версии Terrasoft CRM (например, 3.4.1.148).

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

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

Ответьте пожалуйста на следующие вопросы:
* В момент перехода в раздел или открытия карточки редактирования записи, запросы к серверу уходят?
* Сервер отдает результат запроса?
* В какой момент времени приложение перестает отвечать, в момент отправки запроса на сервер, в момент ожидания ответа или в момент обработки данных?

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

Здравствуйте! Встала задача добавить для сущности Заказы вычисляемое поле, которое представляет собой разность полей Итого (Amount) и Суперкомиссия (UsrSuperFee). Создал такое поле по примеру из документации. Но так как это поле заполняется только в модели при выполнении метода onEntityInitialized() при загрузке карточки редактирования заказа, появляется кнопка "Сохранить" для сохранения этого значения в базу. Если же вынести вычисляемое поле в раздел Заказов, то там в этом поле будут, естественно, одни нули, потому что метод onEntityInitialized() здесь не выполняется.

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

Нравится

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

Добрый день Дмитрий!!!

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

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

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

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

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

Да, именно эту задачу мне требуется решить.

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

В [#Object#]SectionPageV2 нет метода onEntityInitialized(). По этой причине поле не считается, т.к. метод не вызывается.
В [#Object#]SectionPageV2 есть метод initData(), который Вы можете расширить для решения этой задачи.

"Демьяник Алексей" написал:В [#Object#]SectionPageV2 нет метода onEntityInitialized(). По этой причине поле не считается, т.к. метод не вызывается.

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

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

Алексей, не подскажете, как из initData() получить доступ к коллекции элементов заказов раздела, чтобы вставить логику расчета разности двух полей и поместить его в третье?

"Дмитрий Д." написал:Алексей, не подскажете, как из initData() получить доступ к коллекции элементов заказов раздела, чтобы вставить логику расчета разности двух полей и поместить его в третье?

Добрый день Дмитрий!!!

при инициализации раздела и получение Потока Данных у вас не получится выполнить заполнение Вычисляемого поля. Для этого вам требуется создать отдельный бизнес-процесс который при срабатывание определенных условий на входе пересчитывал бы Одно данное поле в базе данных, а в разделе вы бы уже видели результат. Но и данный метод я бы сказал является ошибочным, так как если в Таблице будет Миллион записей, то на пересчет потребуется очень огромное количество времени и ресурсов. Это неверный подход. В опубликованной Вами ссылке Как добавить вычисляемое поле описан алгоритм создания вычисляемого поля для карточки редактирования. Рекомендую именно в карточки редактирования разместить данное вычисляемое поле. А в разделе еще раз повторюсь отображать только результат вычисления.

В дополнении к рекомендации заполнять данные в карточке, могу предложить для случаев, когда в карточке поле еще не рассчитано, но в реестре уже хочется видеть эту информацию:
1. Вывести в реестр данную физическую колонку, которую вы будете вычислять в карточке.
2. В схеме реестра, переопределить метод «addItemsToGridData», который срабатывает при загрузке порции данных в реестр. Т.к. реестр не отображает миллион строк, а только небольшими порциями (по 15 строк) удовлетворяющими фильтрацию, плюс при прокрутке вниз. Так же загружает все порциями, и в этот момент так же срабатывает метод «addItemsToGridData».
3. В методе для незаполненных строк, производить любые вычисления, и заполнять любые существующие колонки. (Важно: данные не уйдут в БД, а будут только информационными. В БД запись делайте при работе с карточкой.)
Пример переопределения метода, в котором я читаю и меняю поле Title строк. По аналогии можно читать и менять любое поле:

addItemsToGridData: function() {
   this.callParent(arguments);
 
   var gridDataItems = this.getGridData().getItems();
   gridDataItems.forEach(function(item) {
      var oldTitle = item.get("Title");
      item.set("Title", oldTitle + "!!!");
   }, this);
 
   console.log("new items loaded");
}

P.S. Так же думая об оптимизации при прокрутке реестра, не забудьте анализировать что поле уже заполнено к примеру так: if (item.get("Title")) { тут логика } что бы не выполнять лишние операции.
В моем случае это не имеет смысла, Title у меня и так всегда заполнен, и пример исключительно тестовый.

Еще немного оптимизации, анализ в методе только новой добавочной (15 строк) коллекции, зачем бегать по всему реестру, если там уже все рассчитано:

addItemsToGridData: function(dataCollection, options) {
	// forEach only new
	dataCollection.getItems().forEach(function(item) {
		var oldTitle = item.get("Title");
		item.set("Title", oldTitle + "!!!");
	}, this);
 
	this.callParent(arguments);
	console.log("new items loaded");
}

Спасибо Максим. Идея очень интересная. Попробую у себя так же протестировать. Только вот вопрос, что будет если колонка "Title" не будет добавлена в Реестр раздела. Ошибка будет или нет выдаваться. Попробую протестировать. Ведь пользователь любит добавлять и удалять преднастроенные колонки.

Максим, спасибо! Уже близко к истине. Только, насколько я понимаю, item в методе addItemsToGridData есть ViewModel, поэтому если какой-либо столбец не выводится в разделе, доступ к нему посредством метода item.get() невозможен. В этом случае нужно будет получать значения полей запросом к базе.

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

Благодарю.

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

Добрый день Дмитрий!!!

как решить вашу задачу описал Илья Мотков в следующем инциденте. Последняя активность в реестре контрагентов посмотрите пожалуйста и по аналогии можно решить и вашу задачу.

Да, там всегда есть ID записи, по которой можно сделать esq, но в этом мало смысла, так как есть метод «initQueryColumns», который и определяет список загружаемых в модель колонок.
Можно заставить загружаться все колонки в модель, что несколько замедлит загрузку реестра:

initQueryColumns: function(esq) {
	this.callParent(arguments);
	this.addAllColumns(esq);
}

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

initQueryColumns: function(entitySchemaQuery) {
   this.callParent(arguments);
   if (!entitySchemaQuery.columns.contains("IntegrationId")) {
      entitySchemaQuery.addColumn("IntegrationId");
   }
},

Разом изменить все существующие записи, можете либо бизнес процессом, либо SQL запросом.
В первом случае логику будете писать на C#, во втором на Transact-SQL.
Это если вы имеете в виду все-все существующие записи, а не только те, что выведены в реестр. И имеете в виду физические данные в базе данных, а не только информационно в реестре. Так как напоминаю, что в реестр данные грузятся порционно.

"Щиголь Максим" написал:Разом изменить все существующие записи, можете либо бизнес процессом, либо SQL запросом.
В первом случае логику будете писать на C#, во втором на Transact-SQL.

Я считаю что данную операцию лучше выполнять разово. Если создавать как постоянную бизнес-логику работы системы, то это может только привести к потере производительности, как я уже говорил выше всегда нужно помнить что рано или поздно количество записей в Таблице может достигнуть Миллиона записей и SQL серверу будет очень тяжело исполнять описанную бизне-логику.

Можете подсказать пример написания и выполнения SQL-скрипта в bpm'online 7.7? Что-то не нахожу подобного в документации.

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

Собственно, необходимо для каждого Order вычесть из поля Amount поле UsrSuperFee и вставить результат в поле UsrAmountWithSuperFee.

"Дмитрий Д." написал:

Можете подсказать пример написания и выполнения SQL-скрипта в bpm'online 7.7? Что-то не нахожу подобного в документации.

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

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

"Дмитрий Д." написал:Собственно, необходимо для каждого Order вычесть из поля Amount поле UsrSuperFee и вставить результат в поле UsrAmountWithSuperFee.

вот Дмитрий сам запрос на обновление

update p set
p.UsrAmountWithSuperFee = p.Amount - p.UsrSuperFee
from Order as p

Спасибо, Алексей и Михаил, за помощь!
Я так решил: если нужно, чтобы вычисляемое поле объекта получало значение в зависимости от значений других полей, то сначала необходимо прогнать всю таблицу sql-запросом для заполнения вычисляемого поля, а уже в карточке редактирования объекта реализовывать логику пересчета его значения при необходимости.

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

Создал простой view

SELECT        '{BA64970A-1B0B-483F-ACE9-E2DAF7A89AF4}' AS ID, 'Да' AS Name
UNION
SELECT        '{36C2640F-B03E-4EA3-96B0-78992A6F86C6}' AS ID, 'Нет' AS Name

в администраторе создал сервис таблицы, создал сервисы Select и Dataset, прикрутил в качестве справочника к нужной таблице. При сохранении записи основной таблицы, поле со значением из такого справочника не сохраняется. Почему?

В качестве справочника не использую перечисление по той причине, что при попытке изменить свойство IsRequired во время выполнения, в версии 3.0 происходит "Разрушительный сбой..."

Нравится

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

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

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

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

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

"Андросов Дмитрий" написал:

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


Согласна, что это может быть возможной причиной.

Проверьте, предположение Дмитрия.

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

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

Добрый день!!!

странно как то, что в Terrasoft 3.X в схеме Таблицы привязанный Вьювер смог сгенерировать Запросы на добавление, обновление, удаление. И система дала их исполнить. На сколько я помню по умолчанию данный функционал отсутствовал. И пришлось бы на уровне SQL сервера создать свои триггеры у Вьювера на создание, обновление, удаление записи.

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

При создании письма из карточки заказа открывается карточка письма. На вкладке "Основная информация" проставлен связанный с ним заказ. Где идет обработка данной операции? Разве не в коде карточки EmailPageV2 пакета Order?

entitySchemaName: "Activity",
                        methods: {
                                /**
                                 * Копирует значения колонок из схемы в текущую модель.
                                 * @overridden
                                 * @param {Object} entity Схема активности.
                                 */

                                copyEntityColumnValues: function(entity) {
                                        var order = entity.get("Order");
                                        if (order) {
                                                this.set("Order", order);
                                        }
                                        this.callParent(arguments);
                                },

                                /**
                                 * Возвращает массив загружаемых колонок.
                                 * @private
                                 * @overridden
                                 * @return {Array} Массив колонок.
                                 */

                                getEmailSelectColumns: function() {
                                        var columnsArray = this.callParent(arguments);
                                        columnsArray.push("Order");
                                        return columnsArray;
                                }
                        },

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

Нравится

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

Нашел вот такую инструкцию на эту тему:
Связывание писем по пользовательскому объекту (например, Лид)
sozdaniesvyazannoyaktivnosti.doc

А нельзя реализовать подстановку контакта аналогично подстановке заказа?

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

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

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

я немного вас не понял, вы желаете чтобы при создание Письма из Заказа заполнялись бы и другие поля в карточки Письма из Заказа, помимо Реквизита "Заказ". Я правильно вас понял, или вы желаете что-то другое выполнить при создание Письма из карточки Заказа?

Смотрите, при создании письма из заказа у нас автоматически заполняется поле Заказ детали Связи вкладки Основная информация. Поле Контакт остается пустым. Следующим этапом происходит следующее:
1.Встаем в поле Заказ
2.Открывается список доступных заказов для выбора
3.Выбираем тот же самый (!) заказ
4.Поле Заказ заполнено, поле Контакт заполнено.
Следовательно при выборе другого или того же самого элемента в данной детали - обновляются связи, и поля заполняются, в соответствии с тем, как они заполнены в карточке заказа.
Потому такой вопрос: можно ли как то при инициализации карточки вызвать тот же самый метод, который срабатывает при смене значения поля Заказ детали Связи? И если возможно, то как называется данный метод?

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

getAddButtonMenuVisible: function() {
   return true;
},

В карточке заказа. Или из какой вы карточки создаете письмо, ваш второй комментарий вводит в заблуждение. Если же вы добавляете письмо через деталь «Письма» в заказе, то связь и так проставляется, делать для этого ничего не нужно.

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

setAdditionalDefValues: function(openCardConfig, next) {
	if (this.entitySchema.name === "Order") {
		openCardConfig.defaultValues.push({
			name: "Order",
			value: this.get("Id")
		});
		next();
	} else {
		next();
	}
}

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

P.S. за всю логику этой кнопки быстрого добавления активностей(писем) отвечает схема(миксин) QuickAddMixin, там и инициируется вызов метода setAdditionalDefValues

Никакой кнопки не добавлялось. Пошагово процесс добавления представлен на скриншотах


На скриншотах используется с кодом

setAdditionalDefValues: function(openCardConfig, next) {
        if (this.entitySchema.name === "Order") {
                openCardConfig.defaultValues.push({
                        name: "Order",
                        value: this.get("Id")
                });
                next();
        } else {
                next();
        }
}

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

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

onEntityInitialized: function() {
	this.callParent(arguments);
 
	if(this.get("Order") && (!this.get("Contact"))) {
		var oldOrder = this.get("Order");
		this.set("Order", null);
		this.set("Order", oldOrder);
	}
},

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

Начну попорядку.
1. задача - При выборе заказа, на странице редактирования Активности, заполнять поле контакт.
Решение:

Создаем замещающий модуль страницы редактирования Активности и пишем код:

define("ActivityPageV2", [],
    function() {
        return {
            entitySchemaName: "Activity",
            attributes: {
                /**
                 * Заказ
                 */
                "Order": {
                    dataValueType: this.Terrasoft.DataValueType.LOOKUP,
                    lookupListConfig: {
                        columns: ["Contact"]
                    },
                    dependencies: [
                        {
                            columns: ["Order"],
                            methodName: "onOrderAttributeChange"
                        }
                    ]
                }
            },
            details: /**SCHEMA_DETAILS*/{}/**SCHEMA_DETAILS*/,
            methods: {
                /**
                 * Заполняем поле контакт, после выбора Заказа
                 * @private
                 */
                onOrderAttributeChange: function() {
                    var order = this.get("order");
                    if (order) {
                        var contactOrder = order.Contact;
                        if (contactOrder) {
                            this.loadLookupDisplayValue("Contact",
contactOrder.value);
                        }
                    }
                }
            },
            diff: /**SCHEMA_DIFF*/[]/**SCHEMA_DIFF*/,
            rules: {}
        };
    });

2 задача - При редактирование карточки Заказа требуется создать Еmail сообщение, при создание карточки редактирования EmailPageV2 заполнить поле контакт. Здесь все так же просто, выполнить замещение страницы редактирования Заказа. И написать следующий код:

define("OrderPageV2", [],
	function() {
		return {
			entitySchemaName: "Order",
			details: /**SCHEMA_DETAILS*/{
				EmailDetailV2: {
					schemaName: "EmailDetailV2",
					entitySchemaName: "Activity",
					filter: {
						masterColumn: "Id",
						detailColumn: "Order"
					},
					defaultValues: {							
						Contact: {masterColumn: "Contact"}
					}
				}
			}/**SCHEMA_DETAILS*/,
			attributes: {},
			methods: {},
			rules: {},
			userCode: {},
			diff: /**SCHEMA_DIFF*/[
			]/**SCHEMA_DIFF*/
		};
	});

все при создание емайл будет заполняться поле Контакт взятое со страницы редактирования Заказа.

"Щиголь Максим" написал:

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

В замещающей схеме EmailPageV2 пишите:

onEntityInitialized: function() {

        this.callParent(arguments);

               

        if(this.get("Order") && (!this.get("Contact"))) {

                var oldOrder = this.get("Order");

                this.set("Order", null);

                this.set("Order", oldOrder);

        }

},

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


Поле контакт заполняется, но вот код из карточки EmailPageV2 пакета UIv2 не отрабатывает, а конкретно функция OnContactChange:

				onContactChange: function() {
					var ext = this.Ext;
					var contact = this.get("Contact");
					var recipient = this.get("Recepient");
					if (ext.isEmpty(recipient) && !ext.isEmpty(contact) && !ext.isEmpty(contact.Email)) {
						var email = ext.String.format(this.get("Resources.Strings.EmailFormatString"),
							contact.displayValue, contact.Email);
						this.set("Recepient", email);
					}
				},

А именно в условии !ext.isEmpty(contact.Email) не выполняется, в отладчике пишет что contact.Email - пустое.

"Бахматов Александр Валерьевич" написал:Поле контакт заполняется, но вот код из карточки EmailPageV2 пакета UIv2 не отрабатывает, а конкретно функция OnContactChange:

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

я в своих сообщениях ответил полностью на ваши вопросы и описал как решить ваши задачи. По вопросу работы функции OnContactChange, на память не помню как она срабатывает, но судя даже по названию срабатывает при изменение контакта, и подстановки заполненного Email у контакта в поле "Recepient". вот как работает данная функция, что вас не устраивает в работе данной функции?

"Власов Михаил Викторович" написал:что вас не устраивает в работе данной функции?

Срабатывать она срабатывает, но в отладчике видно, что в объекте Contact не заполняются поля. Т.е. заполняется лишь display_value и value, в то время как должны еще заполняться поля Email и т.д. Потому if не отрабатывает и Recepient не заполняется в карточке.

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

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

            attributes: {
                /**
                 * Контакт
                 */
                "Contact": {
                    lookupListConfig: {
                        columns: ["Email"]
                    }
                }
            }

вот только при таком описание Аттрибута контакт сработает следующий ваш код:

 ...
 if (ext.isEmpty(recipient) && !ext.isEmpty(contact) && !ext.isEmpty(contact.Email)) {
     ....
 }

Т.е. добавив этот атрибут, мы добавили его в возвращаемый объект и потому теперь заполняются поля display_value, value и email? Я правильно понимаю логику этой замены?

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

описывая Атрибут Контакт добавляя:

   lookupListConfig: {
      columns: ["Email"]
   }

вы тем самым даете инструкцию при генерации и открытие страницы, что при формирование Выборки требуется еще для Атрибута "Контакт" выбрать его Емайл. И далее уже в коде проверяем если Контакт заполнен, то легко выбираем Емайл контакты выполнив инструкцию "contact.Email". Вот и все!!

если что непонятно написал, пишите перефразирую свою мысль.

Т.е., если мне понадобится обратиться к какому то атрибуту, я должен буду добавлять его в карточку, на примере Email?

"Бахматов Александр Валерьевич" написал:Т.е., если мне понадобится обратиться к какому то атрибуту, я должен буду добавлять его в карточку, на примере Email?

Александр если вам требуется получить Реквизит из другой сущности, как в вашем примере на карточке редактирования Емайл вам требуется получить Емайл контакта. то вам нужно именно в карточке редактирования описать следующее:

повторюсь еще раз

            attributes: {
                /**
                 * Контакт
                 */
                "Contact": {
                    lookupListConfig: {
                        columns: ["Email"]
                    }
                }
            }

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

Спасибо за объяснение!

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

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

1. Название последней активности
2. Статус последней активности
3. Другие поля. Например, ответственный, даты и.т.д. т.е. любые поля сущности Активность.

И что бы все это отображалось в реестре, вид Плиточный.

Нравится

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

Добрый день Петр!!!

подскажите пожалуйста а какую цель вы преследуете, выполняя и выполнив описанную вами задачу? не легче настроить раздел Активности по описанным вами выше кретериям, создав разные преднастроенные Динамические фильтры. Я думаю идти от обратного всегда легче. Так как выполняя вашу задачу в разделе контрагенты система Автоматически будет генерить Левые соединение или Вложенные запросы, а это дополнительная нагрузка на SQL сервер.

Михаил, цель - чтобы визуально видеть какое последнее действие по контрагенту было не заходя в карточку контрагента. При формировании динамического фильтра таже проблема возникает:
- нельзя отфильтровать кнтрагента по названию последней активности
- нельзя отфильтровать по другим колонкам конкретной активности https://yadi.sk/i/ycf23ySBrpEBG

Мы не можем датой подыгрывать, т.к. может эта последняя задача 3 месяца назад начата и незакончена, а может быть назначена на 3 месяца вперёд

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

Как вариант добавить новые колонки в объект раздела (через тот же мастер раздела), и при добавлении данных на деталь запускать бизнес-процесс, который данные с таблицы детали будет переносить в колонку объекта. Другой вопрос, что средств связи и адресов с одним типом может быть несколько. Эту логику необходимо предосмотреть в бизнес-процессе.

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

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