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

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

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

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

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

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

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

Нравится

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

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

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

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

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

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

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

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

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

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

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

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

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

Вот.

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

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

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

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

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

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

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

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

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

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

Победа.

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

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

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

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

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

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

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

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

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

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

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

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

Илья,

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

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

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

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

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

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

Здравствуйте! Продукт sales enterprice 7.9.0.
Необходимо принудительно сортировать записи на детали по колонке "Дата создания" по возрастанию.
При этом пользователь должен иметь возможность сортировать записи по своему усмотрению с помощью стандартных средств сортировки на детали. Но при добавлении новой записи на детали должна снова применяться принудительная сортировка скриптом записей по возрастанию даты создания. Как это реализовать?

Вот код:

details: /**SCHEMA_DETAILS*/{
"UsrCommerceOfferForSale": {
"schemaName": "UsrCommerceOfferForSale",
"entitySchemaName": "UsrOfferForSale",
"filter": {
"detailColumn": "UsrOffers",
"masterColumn": "Id"
},
"filterMethod": "UsrCommerceOfferForSaleFilter"
}
},

methods: {
UsrCommerceOfferForSaleFilter: function() {
var filterGroup = new Terrasoft.createFilterGroup();
filterGroup.add("UsrCommerceOfferForSaleByUsrOffers", Terrasoft.createColumnFilterWithParameter(
Terrasoft.ComparisonType.EQUAL, "UsrOffers", this.get("Id")));
/* Фильтр по одному значению */
filterGroup.add("CreatedOn", Terrasoft.createColumnFilterWithParameter(
Terrasoft.ComparisonType.EQUAL,
//Здесь непонятно, как отсортировать по возрастанию даты создания
return filterGroup;
},
}

Нравится

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

Сомневаюсь, что в фильтре можно задавать сортировку. Я бы смотрел:
1) В сторону метода заполнения коллекции GridData в детали. Желательно докопаться до esq запроса в бд и вставить что-то вроде

var col = esq.addColumn("CreatedOn");
col.orderDirection = Terrasoft.OrderDirection.ASC;
col.orderPosition = 0;

2) В описании Grid(опять же в детали) в diff вроде есть

"sortColumn": {"bindTo": "sortColumn"},
"sortColumnDirection": {"bindTo": "GridSortDirection"},
"sortColumnIndex": {"bindTo": "SortColumnIndex"}

Скорее всего и тут можно задать

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

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

Скелет класса CaseRatingService (клон CaseRatingManagementService):

namespace Terrasoft.Configuration.CaseManagementService
{
        using System;
        using System.CodeDom.Compiler;
        using System.Collections.Generic;
        using System.Collections.ObjectModel;
        using System.Data;
        using System.IO;
        using System.Text;
        using System.Threading;
        using System.Threading.Tasks;
        using System.ServiceModel;
        using System.ServiceModel.Web;
        using System.ServiceModel.Activation;
        using System.ServiceModel.Channels;
        using System.Security.Principal;
        using System.Web;
        using Newtonsoft.Json;
        using Newtonsoft.Json.Linq;
        using Terrasoft.Common;
        using Terrasoft.Common.Json;
        using Terrasoft.Core;
        using Terrasoft.Core.DB;
        using Terrasoft.Core.Entities;
        using Terrasoft.Core.Store;
        using Terrasoft.Nui.ServiceModel;
        using Terrasoft.Nui.ServiceModel.Extensions;
        using Terrasoft.UI.WebControls;
       
        #region Class: CaseManagementService
        [ServiceContract]
        [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
        public class CaseManagementService {

                [OperationContract]
                [WebGet(UriTemplate = "Case/{id}/{rating}")]
                public void GetCase(string id, string rating) {
                        var context = HttpContext.Current;
                        try{
                                HttpRequest request = context.Request;
                                if (id == null || rating == null) {
                                        throw new ArgumentNullOrEmptyException("rating");
                                }
                                _appConnection = HttpContext.Current.Application["AppConnection"] as AppConnection;
                                _sysUserName = _appConnection.SystemUserConnection.CurrentUser.Name;
                                _sessionId = Guid.NewGuid().ToString("N");
                                Thread.CurrentPrincipal = new TerrasoftPrincipal(new GenericIdentity(_sysUserName), new string[0], _sessionId);
                                this._setResponseText(context.Response, "Ok");
                        } catch (Exception ex) {
                                this._setResponseText(context.Response, ex.Message);
                        }
                }
               
                #region Fields: Private

                private UserConnection _userConnection;
                private string _sessionId;
                private string _sysUserName;
                private AppConnection _appConnection;

                #endregion

                #region Private property: UserConnection::UserConnection
                private UserConnection UserConnection {
                        get {
                                if (_userConnection != null) {
                                        return _userConnection;
                                }
                                if (HttpContext.Current.Session != null) {
                                        _userConnection = HttpContext.Current.Session["UserConnection"] as UserConnection;
                                }
                                if (_userConnection == null) {
                                        var result = new UserConnection(_appConnection);
                                        result.Initialize();
                                        result.SessionId = _sessionId;
                                        _userConnection = result;
                                }
                                return _userConnection;
                        }
                }
                #endregion     

                #region Private method: _setResponseText(response,text)::void
                private void _setResponseText(HttpResponse response, string text) {
                        var label = string.Format("{0}",
                                text);
                        response.Write(label);
                }
                #endregion
        }
        #endregion
}

Выдает такую ошибку:

Date: 08.12.2016 11:27:01
Date (UTC): 08.12.2016 9:27:01

Exception Message: Не удалось найти тип "Terrasoft.Configuration.CaseManagementService.CaseManagementService", заданный значением атрибута Service в директиве ServiceHost или указанный в элементе конфигурации system.serviceModel/serviceHostingEnvironment/serviceActivations.
Exception Type: System.InvalidOperationException
Exception Source: System.ServiceModel.Activation

Exception Stack Trace:
   в System.ServiceModel.Activation.ServiceHostFactory.CreateServiceHost(String constructorString, Uri[] baseAddresses)
   в System.ServiceModel.ServiceHostingEnvironment.HostingManager.CreateService(String normalizedVirtualPath, EventTraceActivity eventTraceActivity)
   в System.ServiceModel.ServiceHostingEnvironment.HostingManager.ActivateService(ServiceActivationInfo serviceActivationInfo, EventTraceActivity eventTraceActivity)
   в System.ServiceModel.ServiceHostingEnvironment.HostingManager.EnsureServiceAvailable(String normalizedVirtualPath, EventTraceActivity eventTraceActivity)

SessionID: 1r4srdi5za0yv132xnjywfzg
Request URL: /WebApp770/0/ServiceModel/CaseManagementService.svc
Request Path: /WebApp770/0/ServiceModel/CaseManagementService.svc
Request Type: GET
User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36
User Host Address: ::1
User: EFrolov
Is Authenticated: True
Authentication Type: Forms
Is Secure Connection: False

Application Version: 7.7.0.0
Application Path: G:\Projects\Core\TSBpm\Src\Lib\Terrasoft.WebApp.Loader\Terrasoft.WebApp\
Application Virtual Path: /WebApp770/0
Application Trust Level: Full
Machine Name: PC-23-N
Is Local: True

Process ID: 10396
Process Name: iisexpress.exe
Process Account Name: INDOORMEDIA\developer
Thread Account Name: INDOORMEDIA\developer
OS Version: Microsoft Windows NT 6.2.9200.0
Net Framework Version: 4.0.30319.42000
DBExecutor Type: MSSqlExecuto

1. в ServiceModel поцепил файлик CaseManagementService.svc:

%@ ServiceHost Language="C#" Debug="true" Service="Terrasoft.Configuration.CaseManagementService.CaseManagementService" %>

2. в services.config (http и https) :


 
    address=""
    binding="webHttpBinding"
    behaviorConfiguration="RestServiceBehavior"
    bindingNamespace="http://Terrasoft.WebApp.ServiceModel"
    contract="Terrasoft.Configuration.CaseManagementService.CaseManagementService" />

3. в web.config:

...
 
   
     
       
     

   
 

...

...

4. в App.config:

...

...

Нравится

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

Вопрос закрыт.

Совет на будущее:
"ПРОВЕРЯЙТЕ КОНФИГУРАЦИЮ, НА КОТОРОЙ ВС СОЗДАВАЛСЯ И ПОД КАКОЙ ВЫ К НЕМУ СТУЧИТЕСЬ!"

Добрый день!
Имеется следующий пример реализации.
В конфигурации необходимо создать схему исходного кода c контрактом сервиса:
[ServiceContract]
public interface IService
{
[OperationContract]
SPMClientInfoResponse SPMClientInfo(string Login);
}

[DataContract]
public class SPMClientInfoResponse
{
bool success = true;
string errorText = "";

[DataMember]
public bool Success
{
get { return success; }
set { success = value; }
}

[DataMember]
public string ErrorText
{
get { return errorText; }
set { errorText = value; }
}
}

и схему исходного кода c реализацией сервиса:

public class SPMSUBPService : IService
{
public SPMClientInfoResponse SPMClientInfo(string Login)
{
return new SPMClientInfoResponse();
}
}

Методы конфигурационного веб-сервиса должны быть помечены атрибутами [OperationContract] и
[WebInvoke] с параметрами.
Например, вот так: [OperationContract]
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, BodyStyle
= WebMessageBodyStyle.Wrapped, ResponseFormat = WebMessageFormat.Json)]

Далее, в папке В папке Terrasoft.WebApp\ServiceModel создаем файл CaseManagementService.svc с примерно таким текстом:
<%@ ServiceHost Language="C#" Debug="true" Service="CaseManagementService.CaseManagementService" Factory="System.ServiceModel.Activation.ServiceHostFactory" %>

Добавить в файл Terrasoft.WebApp\ServiceModel\http\services.config описание сервиса:

...

...

Модифицировать Terrasoft.WebApp\Web.config

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

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

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

Подскажите на что стоит обратить внимание, в чем может быть проблема? Может кто то сталкивался?

Версия 7.7.0.2284

Нравится

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

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

Нужно смотреть на консольную ошибку. Возможно в названии контрагента есть спец. символы. Точно определить причину по такому описанию нет возможности.

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

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

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

В разделе Документы настроены итоги, записи раздела отфильтрованны по быстрому фильтру даты (например выбран Сегодня), при переходе в другой раздел и возврате в раздел Документы итоги отображаються как если бы фильтра по дате не было, если нажать Сегодня итоги обновляться и отображаться верно.

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

Sales Team Версия 7.7.0.2284

Нравится

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

Быстрый фильтр вроде начал сохраняться при переходах только с 7.8

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

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

Рекомендуем обновиться на 780.

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

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

Нравится

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

Здравствуйте,
В системе есть пример уже, это встраивание видео на главной странице.
Суть написания сводится к использованию контейнера, и написанию в нем произвольного html кода, вплоть до iframe.
Еще пример:

define("CasePage", ["CasePageResources", "terrasoft", "LookupUtilities"],
	function(resources, Terrasoft, LookupUtilities) {
	return {
		entitySchemaName: "Case",
		details: /**SCHEMA_DETAILS*/{}/**SCHEMA_DETAILS*/,
		attributes: {
		},
		diff: /**SCHEMA_DIFF*/[
			{
				"operation": "insert",
				"parentName": "SolutionTab_gridLayout",
				"name": "UsrTest",
				"propertyName": "items",
				"values": {
					"itemType": Terrasoft.ViewItemType.CONTAINER,
					"layout": { "colSpan": 24, "rowSpan": 1, "column": 0, "row": 4 },
					"id": "UsrTest",
					"selectors": {"wrapEl": "#UsrTest"},
					"html": '<iframe name="bpmonline-video" id="bpmonline-video" width="560" height="315"' +
					'src="https://www.youtube.com/embed/XGSy3_Czz8k" frameborder="0" allowfullscreen></iframe>'
				}
			},
		]/**SCHEMA_DIFF*/,
		methods: {
			onEntityInitialized: function() {
				this.callParent(arguments);
				// just for debug:
				document.scope = this;
			}
		},
		rules: {}
	};
});

Только с iframe стоит учитывать, что встраивать можно только те страницы, которые себя в явном виде позволяют встраивать, к примеру, youtube видео, а также протокол передачи должен совпадать, если ваш сайт работает через https, то и страница фрейма должна работать через https.

Большое спасибо!

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

Подскажите, люди добрые!
Начинаем осваивать планировщик в 7.7. Пытаюсь запустить его сценарием из БП:

var userConnection = GetUserConnection>("UserConnection");
string schedulerJobGroupName = "GroupName";
string jobProcessName = "ISSendContacts";
string schedulerJobName = "JobISSendContacts";
int startOffset = 20;
AppScheduler.RemoveJob(schedulerJobName, schedulerJobGroupName);
var job = AppScheduler.CreateProcessJob(schedulerJobName, schedulerJobGroupName, jobProcessName, userConnection.Workspace.Name, userConnection.CurrentUser.Name);
var trigger = new SimpleTriggerImpl(schedulerJobName + "Trigger", schedulerJobGroupName, DateTime.UtcNow.AddSeconds(startOffset));
AppScheduler.Instance.ScheduleJob(job, trigger);
return true;

При условии, что подключил библиотеки в Usings:

Quartz.Impl
Quartz
Quartz.Impl.Triggers
Terrasoft.Core.Scheduler

А при компиляции он ругается на AppScheduler и SimpleTriggerImpl, типа, они не объявлены.
Пробовал перед ними добавлять альясы Usings, например "Terrasoft.Core.Scheduler.AppScheduler", но это тоже не помогло.
Связано ли это с тем, что БП, создающий Job находится в созданном мной отдельном пакете, в котором из зависимостей только базовые пакеты Base и UIv2?

Нравится

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

Повторил этот бизнес процесс с нуля и он заработал без ошибок :)
Вообще странно, но в любом случае, получается, что я сам где-то ошибся.

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

Добрый день!
Нужно создать справочник с страницей редактирования.

Был создан скрытый раздел, и добавлен справочник. Но возникает проблема, при попытке открыть справочник открывает:

как видите в адресной строке пишет: LookupSectionModule/ilayDocReportsSection
и не отображаются записи справочника.
Но после нажатия Вид -> Настроить колонки(или Настроить итоги) и возврата с страницы настройки назад:

и в адресной строке теперь пишет: SectionModuleV2/ilayDocReportsSection

Смотрел в базе как зарегистрирован аналогичный справочник "Библиотека блоков контента" не нашел отличий.
:

эти темы смотрел:
https://community.terrasoft.ru/forum/topic/16288
https://community.terrasoft.ru/forum/topic/13139

Нравится

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

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

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

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

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

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

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

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

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

Дело в том что как раз через мастер и был создан раздел, и "страницой реестра" была указана секция созданного мастером раздела.

И проблема в том, что при открытии наполнения справочника сначала открывается LookupSectionModule/ilayDocReportsSection, а после открытия страницы настройки колонок открывается уже SectionModuleV2/ilayDocReportsSection.

Здравствуйте,
Отличный вопрос. Виной всему вот этот метод:

Если посмотреть схему секции контент блока, Вы увидите, что он переопределен, это же необходимо сделать и Вам в Вашей странице секции, а так же добавить зависимость:

getProfileKey: function() {
   var currentTabName = this.getActiveViewName();
   var schemaName = this.name;
   return schemaName + this.entitySchemaName + "GridSettings" + currentTabName;
}

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

Добрый день, Максим!
Большое спасибо за ответ!

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

На днях озаботились такой проблемой - клиенту надо посмотреть почтовые сообщения за последнюю неделю. И опа :) В стандартном почтовом клиенте средств фильтрации нет никаких, о папках вообще молчу. Решение - выводить в списке активностей еще и e-maily, благо активности и есть.

Реализация занимает 5 минут, поэтому, если кому надо, то вот последовательность действий:

1. Создаем замещающую схему секции активностей (ActivitySectionV2).
2. В ней определяем, что используем. Нам надо по большому счету BaseFiltersGenerateModule и все.
3. В ветке methods сносим фильтр NotEmailFilter, который собственно и убирает из списка активностей e-maily

getFilters: function() {
  var filters = this.callParent(arguments);
  if (filters.contains("NotEmailFilter")) {
     filters.removeByKey("NotEmailFilter");
   }
  return filters;
}

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

Нравится

Поделиться

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

Причем системная настройка "Отображать email в разделе активности" просится в коробочную версию :)

Согласен :)

или прямо в разделе фильтрацию - галочку поставить

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

Используется bpm'online sales 7.7 после перехода с Terrasoft, т.е. все данные были перенесены (порядка 6 млн. активностей). По результату Terrasoft отрабатывает быстрее чем bpm'online. При запуске сайта локально на сервере отрабатывает терпимо, при работе на пользовательских машинах иногда данные вообще не отображаются.

Может кто-то может поделится наработками в вопросе увеличения быстродействия bpm'online on-site: где/как искать проблему, как/что оптимизировать.

Нравится

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

Здравствуйте.
Не совсем корректно сравнивать быстродействие BPM'online и Terrasoft 3.x. Эти систему имеют абсолютно разную архитектуру. Terrasoft 3.x - это классическая 2-звенная (клиент-сервер) система. BPM'online - 3-звенная (клиент-сервер базы данных-сервер приложения). Если время отклика системы значительно отличается на сервере и на клиентской машине, тогда стоит обратить внимание на сетевую составляющую (стабильность, ширина канала, особенно если это Wi-Fi), также нужно обеспечить достаточные ресурсы клиентской машины (часть кода выполняется, именно, на пользовательском ПК). Также рекомендую в connectionstrings.config в строке подключения к Redis-серверу не использовать в качестве адреса localhost или 127.0.0.1 (указать сетевое имя или реальный IP-адрес). В противном случае игнорируются параметры, отвечающие за многопоточность подключения к Redis. Это параметры maxReadPoolSize=; maxWritePoolSize= (находятся в том же файле в той же строке). По умолчанию равны – 25. Желательно устанавливать по количеству пользователей *10.

Олег, а вы в браузере посмотрите сколько запросов идет и как долго они выполняются. Таким образом сможете выявить где тормозит и падает.
Например, в версии 7.2 по умолчанию стоит таймаут в 30 секунд на запрос. В результате любые запросы более менее тяжелые могут отвалиться, и при этом останется висеть лоадер, либо просто ничего не произойдет. Самый простой вариант, руками поменять таймаут на больший. И как показывает практика, больше времени уходит на обработку уже на серверной стороне.

Александр подскажите где эта настройка устанавливается ?

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