Коллеги всем доброго времени суток. Подскажите, кто нибудь работал с событийным слоем Entity.

Написал класс обработчик в качестве примера для обучения скомпилировал приложение упал сайт.

Вот пример класса обработчика:

 

using System;
using System.Web;
using Terrasoft.Core;
using Terrasoft.Core.Entities;
using Terrasoft.Core.Entities.Events;
 
 
namespace Terrasoft.Configuration
{
    [EntityEventListener(SchemaName = "Order")]
    public class OrderEntityEventListener : BaseEntityEventListener
    {
 
        private UserConnection _userConnection;
 
        private LogService _logService;
        public UserConnection UserConnection
        {
            get
            {
                if (_userConnection != null)
                {
                    return _userConnection;
                }
                _userConnection = HttpContext.Current.Session["UserConnection"] as UserConnection;
                if (_userConnection != null)
                {
                    return _userConnection;
                }
                return _userConnection;
            }
 
            set { _userConnection = value; }
        }        
 
        public LogService LogService { get => _logService; set => _logService = value; }
 
        public OrderEntityEventListener()
        {
            LogService = new LogService(UserConnection);
        }
 
        public override void OnInserting(object sender, EntityBeforeEventArgs e)
        {
            try
            {
                base.OnInserting(sender, e);
 
                var systemUserName = UserConnection.CurrentUser.ContactName;
                var systemUserId = UserConnection.CurrentUser.ContactId;
                LogService.RecInfo($"LOG:[OnInserting]:systemUserId: {systemUserId}; systemUserName:{systemUserName}");
            }
            catch (Exception exception)
            {
                LogService.RecInfo($"LOG:[OnInserting]:Exception: {exception.Message}; {exception.InnerException}");
            }
 
        }
    }
}

Подскажите, что тут не так? Если кто работал, скинте пожалуйста примеры.

Заранее благодарен

Нравится

1 комментарий
Лучший ответ

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

UserConnection необходимо получать из sender

Пример:

public override void OnSaved(object sender, EntityAfterEventArgs e) {

            base.OnSaved(sender, e);

            var entity = (Entity) sender;

            var userConnection = entity.UserConnection;

        }

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

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

UserConnection необходимо получать из sender

Пример:

public override void OnSaved(object sender, EntityAfterEventArgs e) {

            base.OnSaved(sender, e);

            var entity = (Entity) sender;

            var userConnection = entity.UserConnection;

        }

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

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

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



После прочтения документации вижу так:

  1. настроить необходимое в разделе [Лиды] в CRM
  2. сформировать ссылку в письме с нужными параметрами
  3. на сайте проверять параметры в ссылке

  4. при необходимости ставить куку - флаг первого посещения
  5. если посещение первое, то динамически создавать и программно сабмитить форму

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

Нравится

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

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

http://адрес_сайта.com/0/ServiceModel/GeneratedObjectWebFormService.svc/SaveWebFormObjectData

Клиентская логика — в общедоступных скриптах:

https://webtracking-v01.bpmonline.com/JS/track-cookies.js
https://webtracking-v01.bpmonline.com/JS/create-object.js

Серверная — в схеме GeneratedObjectWebFormService.

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

Спрашивали - отвечаем.

Если в ссылке будет передан параметр bpmContactEmail="email@email.email", этот код зарегистрирует лида и привяжет к контакту с почтовым ящиком email@email.email. Ловушка для лида должна быть настроена в разделе [Лендинги].

/*Форма авторегистрации по ссылке из Email*/
					var configAutoReg = {
						fields: {
							"Email": ".bpm-contact-email" // Email посетителя
						},
					    landingId: "00000000-0000-0000-0000-000000000000", // ID лендинга, смотреть в шаге 2 настройки лендинга
					    serviceUrl: "http://CRM_SITE_DNS_NAME/0/ServiceModel/GeneratedWebFormService.svc/SaveWebFormLeadData",
						redirectUrl: ""
					};
					function createLeadFromAutoReg() {
						landing.createObjectFromLanding(configAutoReg)
					};
 
					//функция позволяет выполнять действие (регистрацию лида) один раз
					//взята тут https://developer.mozilla.org/ru/docs/Web/API/Document/cookie#Example_5_Do_something_only_once_%E2%80%93_a_general_library
					function executeOnce () {
						var argc = arguments.length, bImplGlob = typeof arguments[argc - 1] === "string";
						if (bImplGlob) { argc++; }
						if (argc < 3) { throw new TypeError("executeOnce - not enough arguments"); }
						var fExec = arguments[0], sKey = arguments[argc - 2];
						if (typeof fExec !== "function") { throw new TypeError("executeOnce - first argument must be a function"); }
						if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { throw new TypeError("executeOnce - invalid identifier"); }
						if (decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) === "1") { return false; }
						fExec.apply(argc > 3 ? arguments[1] : null, argc > 4 ? Array.prototype.slice.call(arguments, 2, argc - 2) : []);
						document.cookie = encodeURIComponent(sKey) + "=1; expires=Fri, 31 Dec 9999 23:59:59 GMT" + (bImplGlob || !arguments[argc - 1] ? "; path=/" : "");
						return true;
					};
 
					// функция возвращает значение указанного парметра из ссылки
					function getSearchParams(k){
						var p={};
						location.search.replace(/[?&]+([^=&]+)=([^&]*)/gi,function(s,k,v){p[k]=v})
						return k?p[k]:p;
					};
 
					jQuery(document).ready(function() {
						var bpmContactEmail = getSearchParams("bpmContactEmail");
						if (bpmContactEmail && bpmContactEmail !== "[") {
 
							executeOnce(function() {
								landing.initLanding(configAutoReg);								
								var $form = $("<form />", { style: "display: none;", onSubmit: "createLeadFromAutoReg(); return false" });
								$form.append($("<input />", { class: "bpm-contact-email" , name: "bpmContactEmail", value: bpmContactEmail}));
								$form.appendTo("body").submit().remove();
							},
							"bpmLeadFromEmail");
 
						}
					});

 

Зверев Александр,

да не, все проще оказалось, в bpm все настройки только стандартные, а на сайте легкая доработка :)

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

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

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

Изображение удалено.

Нравится

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

Для решения проблемы попробуйте актуализировать роли.

Если актуализация ролей не решит проблему, попробуйте ещё очистить Redis.

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

Ефанов Иван Александрович пишет:

Скажите, а дело может быть в лицензиях?

Думаю, что дело не в лицензиях.

Проверьте ещё настройку прав доступа к объекту SysDashboard на локальной версии и на тестовом сервере.

Права на операции с объектом SysDashboard отличаются, но даже после того как выставил всем ролям право на добавление, кнопка добавить так и не стала активной.

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

Так и сделал сразу, не помогло к сожалению(

А если открыть пункт «Настроить права доступа», который на Вашем скриншоте не заблокирован, и настроить там?

Ефанов Иван Александрович,

Попробуйте скомпилировать все в конфигурации.

Алла Савельева пишет:

Ефанов Иван Александрович,

Попробуйте скомпилировать все в конфигурации.

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

Если есть два сервера и на одном работает, а на другом — нет, нужно искать отличия. Например, посмотреть SQL-запросы в профайлере в момент открытия режима итогов раздела.

Судя по коду, доступность пунктов меню стандартно реализована в схеме DashboardBuilder и действительно связана с правами на «итог» (SysDashboard). То есть либо в той системе доработаны скрипты этой схемы (но тогда непонятно, почему именно на базе разработки нормально), либо всё же дело в правах.

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

 

Мы такое решали с поддержкой. Решили исправительным запросом на ТОЙ стороне вроде.

Дмитрий Степанов пишет:

Мы такое решали с поддержкой. Решили исправительным запросом на ТОЙ стороне вроде.

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

Если лицензии read only, все кнопки заблокируются.

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

Колодяжный Владислав Эдуардович пишет:

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

Измененных схем нет, да и если бы они были, то через свн прилетели бы и на среду разработки. 

Если бы их не было и права одинаковые, то работало бы тоже одинаково. Ищите разницу либо в правах, либо в логике.

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

Добрый день!

Столкнулся с проблемой, поле справочника Состояние на детали графика оплат и поставок на вкладке Паспорт в заказе, в справочнике два значения (Выполнер/Не выполнен) и более не предвидится.

Хотелось бы переделать в выпадающий список, но у поля State замещающего объекта SupplyPaymentElement в пакете с моими доработками галка "Cписок" снята и задизейблена.

Как теперь это обойти?

Нравится

11 комментариев
Лучший ответ

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

+ MetaData.Schema.D2.["0a3324bb-55c8-4791-b51f-409cfedc6fe2"].E20 true

это добавит признак список к колонке UID которой указан в квадратных скобках

Добавьте нужные Вам значения в справочник 'Состояния элемента графика поставок и оплат'.

Алла Савельева,

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

Борис Леонов,

Вы можете реализовать эту функциональность на уровне карточки редактирования:

                {

                    "operation": "insert",

                    "parentName": "Header",

                    "propertyName": "items",

                    "name": "State",

                    "values": {

                        "bindTo": "State",

                        "contentType": Terrasoft.ContentType.ENUM,

                        "layout": {"column": 12, "row": 3, "colSpan": 12}

                    }

                },

Или же создать не замещающий объект, а унаследованный от SupplyPaymentElement, тогда признак 'Список' у поля 'State' будет доступен.

Алла Савельева,

У вас первый вариант прям получилось осуществить? Я сразу так сделал, только "operation" не "insert", а "merge", не работает на детали, действует только на карточку.

А второй как провернуть, что бы остальную логику не переделывать или обойтись минимальными доработками?

Борис Леонов,

Верно, первый вариант работает только для карточки редактирования - я так и написала.

А для отображения в виде списка в редактируемом реестре подойдет только второй вариант.

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

Алла Савельева,

завтра попробую

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

+ MetaData.Schema.D2.["0a3324bb-55c8-4791-b51f-409cfedc6fe2"].E20 true

это добавит признак список к колонке UID которой указан в квадратных скобках

Колодяжный Владислав Эдуардович,

добавление метаданных работает, спасибо!

Интересно, а в методе getCellControlsConfig это можно как то провернуть?

Зверев Александр,

Благодарю!

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

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

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

Нравится

4 комментария
Лучший ответ

Игорь Г. пишет:

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

Можно настроить элемент "Чтение данных" на получение нужного количества записей.

Для этого в параметрах БП объявляете параметр с типом 'Коллекция объектов' и в значения этого параметра добавляете коллекцию из нужного элемента "Чтение данных": https://prnt.sc/l7j5xs

Нужное количество вычитываемых данных указываете в расширенных параметрах элемента "Чтение данных": https://prnt.sc/l7j69n

А потом в элементе "Задание-сценарий" обращаетесь к параметру процесса и вычитываете из него коллекцию:

var userConnection = UserConnection;

for(int i = 0; i < PCBCollection.Count; i++)

{

        EntitySchema schema2 = userConnection.EntitySchemaManager.GetInstanceByName("BTPatienCardBlock");

        Entity entity2 = schema2.CreateEntity(userConnection);

        entity2.SetDefColumnValues();

        entity2.SetColumnValue("Id", Guid.NewGuid());

        entity2.SetColumnValue("Name",                                       PCBCollection[i].GetTypedColumnValue<string>("Name"));

        entity2.Save();

}

return true;

Данная информация давно прочитана и разобрана. К сожалению, она не дает понимания, можно ли в один шаблон вставить несколько строк повторяющейся информации, так как модуль "Читать данные" - читает данные из первой записи выборки. Не понятно, как собрать эти данные в цикле и потом подтянуть в шаблон.

Здравствуйте! Я вижу тут 2 варианта.

1) Писать свой макрос для шаблона. Описание как делать свой макрос описана здесь - https://academy.terrasoft.ru/documents/technic-sdk/7-13/dobavlenie-obra…

2) Формировать тело письма непосредственно в БП заносить его в переменную процесса, а в элементе отправки письма подставлять параметр - http://prntscr.com/l7fj1f&nbsp;

http://prntscr.com/l7fkqf и так можно наполнить тело письма разными параметрами.

Игорь Г. пишет:

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

Можно настроить элемент "Чтение данных" на получение нужного количества записей.

Для этого в параметрах БП объявляете параметр с типом 'Коллекция объектов' и в значения этого параметра добавляете коллекцию из нужного элемента "Чтение данных": https://prnt.sc/l7j5xs

Нужное количество вычитываемых данных указываете в расширенных параметрах элемента "Чтение данных": https://prnt.sc/l7j69n

А потом в элементе "Задание-сценарий" обращаетесь к параметру процесса и вычитываете из него коллекцию:

var userConnection = UserConnection;

for(int i = 0; i < PCBCollection.Count; i++)

{

        EntitySchema schema2 = userConnection.EntitySchemaManager.GetInstanceByName("BTPatienCardBlock");

        Entity entity2 = schema2.CreateEntity(userConnection);

        entity2.SetDefColumnValues();

        entity2.SetColumnValue("Id", Guid.NewGuid());

        entity2.SetColumnValue("Name",                                       PCBCollection[i].GetTypedColumnValue<string>("Name"));

        entity2.Save();

}

return true;

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

Добрый день!

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

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

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

Нравится

3 комментария
Лучший ответ

Проверьте лог обновлений! ( \tmp\PackageInstallation\Log\install.log)

Те в логе установки посмотрите что ваши схемы объекты и тд попали в пакет и успешно импортировались, что в нем нет ошибок....

Проверьте есть ли в конфигурации объекты с признаком требует генерации в БД.

Попытайтесь перекомпилировать конфигурацию (Всю) или накатить пакет повторно

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

Литвинко Павел,

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

 

Проверьте лог обновлений! ( \tmp\PackageInstallation\Log\install.log)

Те в логе установки посмотрите что ваши схемы объекты и тд попали в пакет и успешно импортировались, что в нем нет ошибок....

Проверьте есть ли в конфигурации объекты с признаком требует генерации в БД.

Попытайтесь перекомпилировать конфигурацию (Всю) или накатить пакет повторно

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

При звонке из задачи нажимаю ПОЗВОНИТЬ. Звоню, звонок сохраняется, но к задаче не привязывается (не появляется на вкладке Звонки и SQL запросом видно, что ActivityId = NULL).

При этом на сервере разработки ОК, на проде - не работает привязка. 

Чего не хватает7

Нравится

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

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

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

У меня 7.11.2 

Если дело не в доработках на тесте, попробуйте обновиться.

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

Добрый день!

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

После сохранения списка выводится одна строка, но с возможностью показать весть список через ссылку "Показать больше"

Список создал для менеджеров, что у них на дашбордах отображалась ТОЛЬКО одна запись на текущий момент. Но по текущей логике менеджер может нажать "Показать больше" и взять в работу другой элемент списка (например, список по лидам)

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

Заранее благодарю!

Нравится

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

Эта логика реализована в схеме ChartModule:

/**
 * Loads data into grid with pageble options.
 * @protected
 */
loadMore: function() {
	this.loadGridData();
},

 И ниже:

}, {
"name": chartId + "_loadMore",
"itemType": Terrasoft.ViewItemType.BUTTON,
"caption": {"bindTo": "Resources.Strings.LoadMoreButtonCaption"},
"click": {"bindTo": "loadMore"},
"controlConfig": {
"style": Terrasoft.controls.ButtonEnums.style.TRANSPARENT,
"imageConfig":  {"bindTo": "Resources.Images.LoadMoreIcon"}
},
"classes": {"wrapperClass": ["load-more-button-class"]},
"visible": {"bindTo": "CanLoadMoreData"}
}]

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

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

Добрый день!

Никто не сталкивался с задачей, что нужно настроить доступ к отдельным записям справочника? (например есть справочник "Специальность" и часть записей в нём нужно скрыть от пользователей определённой функц. роли)

Нравится

3 комментария
Лучший ответ

А такая же настройка доступа к объекту по записям не работает?



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

А такая же настройка доступа к объекту по записям не работает?



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

Да, для объекта справочника можно так же включить администрирование по записям, как и для другой таблицы. При этом автоматически в базе должна создаться таблица Sys...Right. Поскольку справочник не зарегистрирован как раздел, добавить в неё записи можно через базу. Либо попробовать через БП, при помощи блока «Изменить права доступа».

Спасибо за комментарии, решил путём администрирования по записям, а для каждой записи справочника добавил определяющее справочное поле. После этого бизнес-процессом изменил права, согласно значениям справочного поля. Для новых значений также бизнес процессом раздаются права.

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

У меня запускается некоторый БП, в котором почти на старте открывается страница на редактирование, соответственно там создается задача с заголовком, который я прописываю.

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

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

Как быть?

Нравится

5 комментариев
Лучший ответ

БП запускается как по сигналу по какому то действию оператора?

Самое простое решение перед открытием окна менять статус задачи (как вариант добавить в объект какой то признак Передан в работу) И не запускать (или завершать) БП у которых этот признак установлен.

Те

старовый сигнал

проверка что признак не установен

и либо выход

либо установка признака и затем открытие  странички редактирования!

БП запускается как по сигналу по какому то действию оператора?

Самое простое решение перед открытием окна менять статус задачи (как вариант добавить в объект какой то признак Передан в работу) И не запускать (или завершать) БП у которых этот признак установлен.

Те

старовый сигнал

проверка что признак не установен

и либо выход

либо установка признака и затем открытие  странички редактирования!

Григорий Чех,

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

Можно, но очень не советую вам на них завязыватся. Они активно изменяются от версии к версии.

Добрый день, как отметил Григорий лучше иметь признак запуска процесса, но вы можете просматривать текущие задачи по процессам они отображаются у клиента из таблицы  SysProcessElementToDo или через js найти и распарсить элемент(если он есть) такого типа там вшит id записи к которой относится страница редактирования id="ProcessDashboardSchemaNotificationContainer-cce9076d-fa47-49a3-bec5-e53450fc421b-ViewModule_RightSideBarModule_ProcessDashboardModule"

В начале БП свяжите процесс с записью. И затем можно искать такие связи

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