Добрый день!

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

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

Вот пример сортировки которая должна сбрасываться при обновлении страницы:

MyFunc: function() {
	return {
              "ModifiedOn": {path: "ModifiedOn", 
                  orderPosition: 0, 
                  orderDirection: Terrasoft.OrderDirection.DESC 
              }
	};
}

Нравится

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

Это сохраняется не в кеше, а в профиле пользователя.

Сохраняет метод setColumnsProfile в GridUtilitiesV2:

 

setColumnsProfile: function(viewColumnsSettingsProfile, notSaveToProfile) {
			const profile = this.get("Profile");
			if (notSaveToProfile !== true) {
				const gridName = this.getDataGridName();
				if (profile[gridName]) {
					const profileKey = profile[gridName].key;
					Terrasoft.utils.saveUserProfile(profileKey, viewColumnsSettingsProfile, false);
				}
			}
			this.set("Profile", viewColumnsSettingsProfile);
		},

Нужно просто на схеме раздела заместить данный метод, чтобы он ничего не делал:

setColumnsProfile: Terrasoft.emptyFn

 

Это сохраняется не в кеше, а в профиле пользователя.

Сохраняет метод setColumnsProfile в GridUtilitiesV2:

 

setColumnsProfile: function(viewColumnsSettingsProfile, notSaveToProfile) {
			const profile = this.get("Profile");
			if (notSaveToProfile !== true) {
				const gridName = this.getDataGridName();
				if (profile[gridName]) {
					const profileKey = profile[gridName].key;
					Terrasoft.utils.saveUserProfile(profileKey, viewColumnsSettingsProfile, false);
				}
			}
			this.set("Profile", viewColumnsSettingsProfile);
		},

Нужно просто на схеме раздела заместить данный метод, чтобы он ничего не делал:

setColumnsProfile: Terrasoft.emptyFn

 

Владислав Литвинчук,

Благодарю Владислав, да, это то что нужно. Переопределил метод без логики сохранения и всё заработало. Спасибо ещё раз!

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

Добрый день

Имеется ли в црм облаке , способ получать файл напрямую к примеру document.docx

или это можно сделать только с помощью прикрепления на файлы и примечания

Если все таки только файлы и примечания, то как я могу прикрепить туда файл

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

Нравится

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

Если на карточке раздела есть деталь файлы и ссылки обычно это объект {SectionName}File. К примеру для активностей это ActivityFile. 

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

 

Stream stream = new MemoryStream(byteArray);

var size = Convert.ToInt32(stream.Length);

 

var insertActivityFile = new Terrasoft.Configuration.ActivityFile(context.UserConnection);

        insertActivityFile.Id = Guid.NewGuid();

        insertActivityFile.SetDefColumnValues();

        insertActivityFile.Name = "Name.txt";

        insertActivityFile.SetStreamValue("Data", stream);

        insertActivityFile.Size = size;

        insertActivityFile.TypeId = new Guid("529BC2F8-0EE0-DF11-971B-001D60E938C6");

        insertActivityFile.Version = 1;

        insertActivityFile.ActivityId = activityId;

        insertActivityFile.Save();

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

 

Если на карточке раздела есть деталь файлы и ссылки обычно это объект {SectionName}File. К примеру для активностей это ActivityFile. 

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

 

Stream stream = new MemoryStream(byteArray);

var size = Convert.ToInt32(stream.Length);

 

var insertActivityFile = new Terrasoft.Configuration.ActivityFile(context.UserConnection);

        insertActivityFile.Id = Guid.NewGuid();

        insertActivityFile.SetDefColumnValues();

        insertActivityFile.Name = "Name.txt";

        insertActivityFile.SetStreamValue("Data", stream);

        insertActivityFile.Size = size;

        insertActivityFile.TypeId = new Guid("529BC2F8-0EE0-DF11-971B-001D60E938C6");

        insertActivityFile.Version = 1;

        insertActivityFile.ActivityId = activityId;

        insertActivityFile.Save();

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

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

this.showBodyMask()

поверх модульного окна, или справочника?

Нравится

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

По идее можно прокинуть config в функцию, а в конфиге указать селектор.

Подробнее посмотрите тут, в функции show.

Небольшой оффтоп: Там в функции createMask можно накидать и caption для маски, и прозрачность менять, и бэкграунд... Почему это нигде не задокументировано - ума не приложу. Наиполезнейшая вещь иногда.

По идее можно прокинуть config в функцию, а в конфиге указать селектор.

Подробнее посмотрите тут, в функции show.

Небольшой оффтоп: Там в функции createMask можно накидать и caption для маски, и прозрачность менять, и бэкграунд... Почему это нигде не задокументировано - ума не приложу. Наиполезнейшая вещь иногда.

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

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

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

Как заставить ее быстро загружаться в фоновой вкладке?

Нравится

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

Здравствуйте, Алексей!



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



Мы передали ваше пожелание аналитикам продукта. Они рассмотрят возможность изменения базовых принципов загрузки страниц приложения в будущих версиях системы.

Анна Журавель,

Да я в целом не против :)

Просто хочется иметь возможность настройки.

Алексей-Карягин,

Спасибо за обратную связь. Мы учтем Ваше пожелание.

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

Доброго времени суток, есть вопрос следующего характера
У меня есть расширяющий модуль для FileDetailV2
Внутри него я получаю контент PDF документа (контент строкой)
Каким образом мне этот контент передать на FileApiService модуль в метод Upload что бы загрузить этот файл?
Если я загружаю руками документ то получаю в консоли POST запрос на

https://testDomain.bpmonline.com/0/rest/FileApiService/Upload?fileapi14996709535744&totalFileLength=47386&fileId=file_id&mimeType=application%2Fpdf&columnName=Data&fileName=20846491.pdf&parentColumnName=Document&parentColumnValue=parent_document_value&entitySchemaName=DocumentFile

И также интересно как в JS получить текущий entitySchemaName?

Нравится

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

Сформируйте аналогичный запрос со значениями колонок в url, и с данными файла в теле запроса средствами js.
Ответ на второй вопрос:

"Максим Шевченко" написал:file_id

Спаибо за Ваш ответ
Но в url есть значение file_id откуда мне его взять если файл еще не создан?

"Nickstery" написал:Но в url есть значение file_id откуда мне его взять если файл еще не создан?

Это просто новый рандомный гуид по которому далее файл можно будет получить, создать новый гуид можно следующим образом:
https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascri…

"Максим Шевченко" написал:
Nickstery пишет:

Но в url есть значение file_id откуда мне его взять если файл еще не создан?

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

https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript

С формированием параметра понятно
Каким образом отправлять контент файла в теле запроса, это form-data по ключу определенному или передаеться как binary data?
Если я формирую запрос в Postman (приложение для отправки запросов) как приведено ниже

http://joxi.ru/V2VKJBwuxeDROA

Я получаю следующий ответ:

http://joxi.ru/L21bq0kh8Jx3dA

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

Я набросал кусок кода, который получает контент файла, формирует BLOB и пытаеться отправить его на FilApiService Только я получаю ту же ошибку

window.console.log("Try to grab the file content");
var http = new XMLHttpRequest();
http.open("get", "https://b981fab7.ngrok.io/getPDF", true);
http.responseType = "arraybuffer";
http.onload = function(e) {
    if (this.status === 200) {
        var uInt8Array = new Uint8Array(this.response);
        var i = uInt8Array.length;
        var binaryString = new Array(i);
        while (i--)
        {
             binaryString[i] = String.fromCharCode(uInt8Array[i]);
         }
        var data = binaryString.join("");
 
        var http2 = new XMLHttpRequest();
        http2.open("post", "/0/rest/FileApiService/Upload?fileapi14998570381414&totalFileLength=47386&" +
        "fileId=*****&mimeType=application/pdf&columnName=Data" +
        "&fileName=20846491.pdf&parentColumnName=Document" +
        "&parentColumnValue=***&entitySchemaName=DocumentFile", true);
        http2.onload = function(e) {
             window.console.log("UPLOAD FILE OPERATION DONE");
             window.console.log(e);
        };
        http2.send(new Blob([data]));
 
        }
    };
http.send();

Разобрался:
Суть в том что при расширении FileDatailV2 (логично) мы унаследуем и методы оринильного модуля.
Можно не использовать FileApiService и не генерировать 100500 параметров а просто обойтись готовым решением, как это делает аплоад документа юзер, который находится в CRM.
Достаточно использовать FileDetailV2 -> onFileSelect метод и из строчного контента сгенерировать window.File
Пример как я это реализовал ниже:

window.console.log("Try to grab the file content");
var http = new XMLHttpRequest();
http.open("get", "https://b981fab7.ngrok.io/getPDF", true);
http.responseType = "blob";
var parent = this;
http.onload = function(e) {
    if (http.readyState === 4) {
    var blob = http.response;
    parent.onFileSelect([new window.File([blob], "UPLOADED.pdf")]);
    }
};
http.send();

Таким образом не нужно думать как приатачить документ в таблицу после его загрузи, это все делает модуль автоматически

У меня задача как раз стоит чтобы загрузить файл, но не из интерфейса приложения, а сторонним приложением. И мне необходимо использовать FileApiService. Как правильно им пользоваться? Может кто нибудь показать рабочий пример кода?

Руслан, пример есть здесь, а увидеть, какие запросы отправляются сервису можно в Fiddler и подобных инструментах.

Установил фидлер и при включенном захвате трафика выходит такая ошибка:

Зато удалось в консоли разработчика увидеть запрос отправленный на сервер:

https://my.domain.com/0/rest/FileApiService/Upload?fileapi1606730904835…

При попытке отправить этот запрос из POSTMAN, сервер возвращает ошибку: 

400 Bad request

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

Отловил запрос прямо в браузере, вот:

https://my.domain.com/0/rest/FileApiService/Upload?fileapi1606730904835…

Но при попытке отправить этот запрос из POSTMAN, сервер возвращает ошибку: 

400 Bad request

Можно попробовать сравнить запрос с нормально работающим, поискать в чём отличия в содержимом.

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

Так в том и вопрос, какой он нормально работающий запрос. Я ни как не могу его найти. Могли бы вы предоставить пример рабочего запроса? Буду очень признателен.

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

Request URL: https://0987561-se-m-se-demo.creatio.com/0/rest/FileApiService/Upload?fileapi16068281951725&totalFileLength=42738&fileId=0015222a-e192-4e2d-a305-7029653b76eb&mimeType=image%2Fpng&columnName=Data&fileName=test.png&parentColumnName=Contact&parentColumnValue=eba7839a-6dff-430f-8325-fb8e02546348&entitySchemaName=ContactFile
Request Method: POST
Status Code: 200 
Remote Address: 40.91.213.136:443
Referrer Policy: strict-origin-when-cross-origin
cache-control: private
content-type: application/json; charset=utf-8
date: Tue, 01 Dec 2020 13:16:21 GMT
server: Microsoft-IIS/10.0
status: 200
x-aspnet-version: 4.0.30319
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-powered-by: ASP.NET
:authority: 0987561-se-m-se-demo.creatio.com
:method: POST
:path: /0/rest/FileApiService/Upload?fileapi16068281951725&totalFileLength=42738&fileId=0015222a-e192-4e2d-a305-7029653b76eb&mimeType=image%2Fpng&columnName=Data&fileName=test.png&parentColumnName=Contact&parentColumnValue=eba7839a-6dff-430f-8325-fb8e02546348&entitySchemaName=ContactFile
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: en-US,en;q=0.9,uk;q=0.8,ru;q=0.7
bpmcsrf
content-disposition: attachment; filename=test.png
content-length: 42738
content-range: bytes 0-42737/42738
content-type: image/png
cookie: BPMSESSIONID=oq1w3q0l1yhedqm43aayja1a; _ga=GA1.2.656850260.1571905584; UserName=83|117|112|101|114|118|105|115|111|114; BPMLOADER=ytih30doaflbq4opdaauindd; _gid=GA1.2.1302014581.1606819455; .ASPXAUTH=0008CA5627819C22386A7FD7673D990C515D14E16AAA7C3E962C321AD5B73C8A2E390A6A6F5AE4DDD258B39ED90AE52BB05619534187DF76BBB1D1FF11B042E75619D72724CFE8E56619EEA9AC684DD352340A7212E60D621B3347E1116DE823140E48AE7FF68CE26734B92A9535C2C69D4BF9A6DE071595ECA44536D4EDF49958CBE863D46ABF8E86B2BAB87496310E5A25A03B4037A458240E6FAB1DFA93DE265821214B9C08D57C5CF3D2376E197C94AC1CF59BE9DA24BE2415465689C40BB1306488AB986D58ADCA8764F99566A0BCBB108248B7FB62678B541F509BC80525781C299A0A5FE2EB0F6997868942D0BD146D40C89B36E12CC760D7C05709175E01F26E6B67BF67846BE78BFE1E583A830ACFFF907A58B713DED3C10FC4E422C74DF27E792BADD1138259551A290978A88414B1CDC15E000D4A44B70BD9E296B74C0601BD3DDD315F2722EC95987F77427E73EB062C147611AD43A0DEE6B967AB07C932
origin: https://0987561-se-m-se-demo.creatio.com
referer: https://0987561-se-m-se-demo.creatio.com/0/Nui/ViewModule.aspx
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: same-origin
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36
x-requested-with: XMLHttpRequest
fileapi16068281951725: 
totalFileLength: 42738
fileId: 0015222a-e192-4e2d-a305-7029653b76eb
mimeType: image%2Fpng
columnName: Data
fileName: test.png
parentColumnName: Contact
parentColumnValue: eba7839a-6dff-430f-8325-fb8e02546348
entitySchemaName: ContactFile
‰PNG

 
IHDRТA7fœsRGB®ÎégAMA±üa

 

Если его, то видел. Но повторить и выполнить самому, для начала из POSTMAN, ни как не получается из-за ошибки 400 Bad request.

Руслан, можно в Fiddler сравнить все заголовки правильного и неправильного запросов, может чего-то не хватать.

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

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

В итоге вроде с виду выглядит всё как надо, результата нет.
Адреса просто не создаются.
С телефонами выдаёт ошибку.
Ошибка импорта. Could not convert variant of type (OleStr) into type (Boolean). Возникла при импорте записи 1C с именем Нова ОсОО Телефон Мобильный

Ещё конечно порадовало "Добавлен новый Елемент")))

Скрины приложил.

Нравится

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

Сложно сказать о конкретных причинах, не видя Ваши 1С и Terrasoft.
Слово «елемент» можно исправить в 47 строке scr_Dataflow1CConsts. И заодно в другом сообщении в 20 строке scr_MsxmlUtils.dash2
Ошибка «Could not convert variant of type (OleStr) into type (Boolean)» говорит, что пытаетесь загрузить строку в логическое поле.

Да мне то "елемент" не мешает, исправлять это в релизе надо. а не в одной копии программы.

1С и ТС вроде у всех одинаковые. 1С УТ 10.3.35.1. Как посмотреть точную версию ТС не знаю.
От того какие там буковки в адресах и телефонах, по моему ничего не меняется.
А настройки обмена, отборы и сопоставление полей я привел на скринах. По всей видимости проблема в них, но где именно не понятно.

"Корниленко Роман Васильевич" написал: исправлять это в релизе надо. а не в одной копии программы.

Роман, разработка 3.Х прекращена, на ней больше релизов не будет.
1С и ТС вроде у всех одинаковые.

Да нет, вроде, у всех разные.

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

"Зверев Александр" написал:Роман, разработка 3.Х прекращена, на ней больше релизов не будет.

Ну ок.
"Зверев Александр" написал:Да нет, вроде, у всех разные.

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

"Корниленко Роман Васильевич" написал:Что Вы подразумеваете под разные?

В разных версиях Terrasoft для работы с разными версиями 1С могут потребоваться определённые доработки в конфигурации.

"Зверев Александр" написал:Сложно сказать о конкретных причинах, не видя Ваши 1С и Terrasoft.

"Зверев Александр" написал:В разных версиях Terrasoft для работы с разными версиями 1С могут потребоваться определённые доработки в конфигурации.
Версию 1С я написал, платформа 8.2.19.130, как посмотреть версию ТС просьба подсказать.

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

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

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

Приветствую!

В BPMonline 7.3 реализовали по действию из раздела запуск импорта данных из сторонней системы. Все отлично и прекрасно, но есть небольшое неудобство - при импорте большого количества данных система "подвисает". Каким образом можно вызвать иконоку "Загрузка" на подобие той, которая отображается при загрузке раздела, чтобы пользователь знал, что происходит обработка данных, и не клацал лихорадочно на F5?

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

Нравится

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

Для этого специально реализован модуль MaskHelper.
В начале процесса вызовите на странице раздела

this.showBodyMask();

А по завершению

this.hideBodyMask();

Премного благодарен

Есть ли способ реализовать данный функционал в 5.4?

В этой статье описан способ включения прогресс бара через обработчик события контролла, можно ли сделать то же самое в коде скрипта (как в 7.3 с помощью модуля MaskHelper)?

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

SearchButton.AjaxEvents.Click.ShowLoadMask = true;

Также можно использовать второй вариант:

Для добавления маски загрузки необходим следующий код:

Page.AddScript(string.Format("PageContainer.el.mask('{0}', 'x-mask-loading blue', true, false, true);", Loading));

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

Page.AddScript(@"PageContainer.el.unmask();");

Подскажите как вывести значок загрузки для версии CRM 5.2?
Есть кнопка в реестре документов которая отменяет документ - переводит с определенный статус.
При нажатии на кнопку выдается диалоговое окно (Открыть окно сообщения) где спрашивается подтверждение, если "Ок" то процес идет по сообщениею на удаление\отмену. Этот процесс достаточно долгий -- пользователь часто не понимает что происходит, и происходит ли что.

Пробовал:

Page.AddScript(string.Format("PageContainer.el.mask('{0}', 'x-mask-loading blue', true, false, true);", "Отмена или удаление документа"));

Поставить в таске перед действием (уведомить по email, и отменить документ)

И в конце при заврешении данных действий:

Page.AddScript(@"PageContainer.el.unmask();");

Не отображается. Если убрать unmask то значок "Загрузка" показывается и висит пока не обновишь страницу.

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

Картина процесса в атаче.

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

			System.Web.HttpContext httpContext = System.Web.HttpContext.Current;
CultureInfo currentCulture = GeneralResourceStorage.CurrentCulture;
System.Threading.Tasks.Task.Factory.StartNew(() => {
                if (httpContext != null) {
                                System.Web.HttpContext.Current = httpContext;
                }
                GeneralResourceStorage.CurrentCulture = currentCulture;
                try  {
                Method1(UserConnection, Page);
				}	 catch { }
 
 
});

В примере запускается функция Method1.

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

Некоторые собранные мысли, идеи по поводу быстродействия системы Terrasoft CRM

Много чего я взял из тем на форуме и из ответов службы поддержки Террасофт, когда искал как ускорить работу CRM. Возможно, кому-то эта информация будет полезна.

Лабьяк Олег Игоревич пишет:
На быстродействие системы может влиять довольно много параметров. В первую очередь сервер и клиентские места должны удовлетворять аппаратным и программным требованиям для использования программы Terrasoft. Они описаны в документе "Руководство администратора", который поставляется вместе с программой. Также быстродействие зависит от размера базы данных и количества активных подключений к серверу БД.

Проверьте также, включено ли в Вашей базе данных кеширование (для этого необходимо установить значение 1 в колонке UseCache таблицы tbl_DatabaseInfo). Если включена данная опция, память под конкретный экземпляр объекта выделяется только один раз при его создании. При последующих обращениях эти объекты берутся из кеша.

Ещё одна возможная причина - реализация некоторого функционала при открытии раздела. Проверьте профайлером, не выполняются ли в это время запросы, напрямую не связанные с разделом, таблицей tbl_Service и напоминаниями. Очень может нагружать систему использование вызова Services.GetNewItemByUSI(...), особенно в циклах (в результате экземпляр объекта не подтягивается из кеша, а каждый раз создаётся новый экземпляр). Необходимо по возможности этого избегать, используя для получения экземпляров объекта функцию GetSingleItemByCode.

Михайлюк Юра пишет:
Від себе можу додати, я помітив, що продуктивність залежить від кількості активних (відкритих датасетів). Особливо коли вони знаходяться в режимі редагування. Террасофт рекомендує в деяких випадках вимикати реагування на події і після редагування записів вмикати(Dataset.DisableEvents()/Dataset.EnableEvents()).
Мені в одній із карточок реально вдалося підвищити швидкість відображення разів в 10 лише відключивши у відкритих датасетах (з яких дані лише беруться) режим редагування.

Ще один фактор який мені порадили, по мінімуму прив'язувати таблиці до системи перевірки прав доступу. Можете перевірити на свойому клієнті під Адміністратором (мабуть блок "Адміністрування по записам" або "Групи таблиць" не активний) система завантажується і працює в 1,5 рази швидше.

Осауленко Александр пишет:
Необходимо определиться, клиент тормозит или сервер. Я бы сначала посмотрел на запросы от клиента к серверу (профайлер от sql server).

Источник: Производительность системы
http://community.terrasoft.ua/forum/topic/5291

В этой записи в моем блоге я привожу пример как можно проанализировать время выполнения запросов и работы клиентской части CRM с помощью SQL Profiler:
Тема: Анализ быстродействия CRM с помощью SQL Profiler
http://community.terrasoft.ua/blogs/6030

Служба поддержки Террасофт пишет:
Для увеличения быстродействия открытия окон, при их разработке необходимо учитывать следующее:
1. Минимизировать логику в обработчиках событий OnPrepare, OnShow.
2. Не загромождать окна лишними контролами.
3. Использовать минимальную вложенность контролов.
4. Группировать контролы в отдельные фреймы, в зависимости от их смыслового назначения. Использовать центрирование контролов в фреймах по правому либо по левому краю.
5. Уменьшить использование подсветки записей в реестре. Использование подсветки значительно замедляет работу системы.
6. Отображать минимальное количество колонок в реестре, остальные скрывать.

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

Из личного примера: нужно было ускорить время открытия карточки редактирования задачи. После ранее внесенных изменений с моей стороны она открывалась секунд 5-6. Причину я нашел: подключал слишком громоздкие скрипты (например скрипт окна грида документов - wnd_DocumentsGridArea). Почистил подключаемые скрипты, перенес некоторые функции из подключенных скриптов в сам скрипт окна редактирования задачи. И как результат - окно начало открываться 1-2 секунды. Да, это была моя ошибка, но таким образом я узнал, что количество подключаемых скриптов тоже может влиять на быстродействие.

По этому поводу:

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

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

Также, избегайте зацикливания при подключении скриптов.

Как отключить скрипт из основного скрипта, таким образом исключив затраты на его инициализацию во время загрузки CRM, я описал в следующем посте:
Тема: Обращение к переменным и методам скрипта
http://community.terrasoft.ua/forum/topic/6036

По этому поводу я задал следующий вопрос в Службу поддержки Terrasoft:

Кошкаров Андрей, задавая вопрос, пишет:
Подскажите какие плюсы/минусы использования скриптов и их методов этими способами, как может это повлиять на быстродействие системы:
1. Подключать нужный скрипт в текущий скрипт и обращаться к функциям из подключенного скрипта напрямую, например:
ExportAccountToClient(AccountID);

Минус: это что всегда при инициализации основного скрипта инициализируется и подключенный скрипт, который может быть довольно ресурсоемким.
2. Вызывать метод скрипта через получение этого скрипта из кэша или из БД (если не закеширован). Например:
var scrGeneral1CUtils = Services.GetSingleItemByUSI('scr_General1CUtils');
scrGeneral1CUtils.ScriptControl.Run('ExportAccountToClient', AccountID);

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

Ответ был полезным для меня:

Служба поддержки Террасофт пишет:
В общем, Вы описали один из методов оптимизации, который мы использовали при написании базовой конфигурации 3.3.2.
Из scr_Main было убрано явное и косвенное использование scr_UserReportCommon, в результате 3.3.2 стало запускаться почти в 2 раза быстрее, чем 3.3.1.

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

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

scrGeneral1CUtils.ScriptControl.Run('ExportAccountToClient', AccountID);

а вот такой вариант:
scrGeneral1CUtils.ScriptControl.CodeObject.ExportAccountToClient(AccountID);

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

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

Из личного опыта:

Кошкаров Андрей пишет:
Благодаря использованию конструкций кода, вместо подключения скриптов к главному скрипту (пример):
function GetIsOLAPControlIstalled_() {
        if (!Assigned(Main.scrOLAPUtils)) {
                Main.scrOLAPUtils = Services.GetSingleItemByUSI('scr_OLAPUtils');
        }
        return Main.scrOLAPUtils.ScriptControl.CodeObject.GetIsOLAPControlIstalled();
}

....
        if ((WorkspaceUSI == 'wnd_OLAPWorkspace') &&
                (!GetIsOLAPControlIstalled_())) {
....
  • получилось ускорить время загрузки CRM с активным разделом "Контрагенты".
  • Показатели были получены при запуске на тестовом компьютере (процессор Intel Celeron 600 MHz, 256 Мб ОЗУ):
    До:
    Серверная часть (сек)| Клиентская часть (сек) | Общее время (сек)
    1.581 | 196.898 | 198.409
    После:
    Серверная часть (сек)| Клиентская часть (сек) | Общее время (сек)
    1.274 | 123.109 | 124.329
    Итого общее время было уменьшено с приблизительно 3 мин. 20 сек до 2 мин. 4 сек., благодаря уменьшению времени на выполнение операций, выполняемых клиентской частью CRM.

  • ускорить время открытия карточки редактирования записи контрагента:
  • До:
    Серверная часть (сек)| Клиентская часть (сек) | Общее время (сек)
    0.019 | 18.848 | 18.863
    После:
    Серверная часть (сек)| Клиентская часть (сек) | Общее время (сек)
    0.021 | 6.463 | 6.481
    Итого общее время было уменьшено с приблизительно 19 сек до 6.5 сек.

  • ускорить время инициализации раздела "Задачи":
  • До:
    Серверная часть (сек)| Клиентская часть (сек) | Общее время (сек)
    2.875 | 27.772 | 30.620
    После:
    Серверная часть (сек)| Клиентская часть (сек) | Общее время (сек)
    0.077 | 18.441 | 18.509
    Итого общее время было уменьшено с приблизительно 28 сек до 18.5 сек.

  • ускорить время инициализации карточки редактирования задачи:
  • До:
    Серверная часть (сек)| Клиентская часть (сек) | Общее время (сек)
    0.073 | 21.738 | 21.804
    После:
    Серверная часть (сек)| Клиентская часть (сек) | Общее время (сек)
    0.039 | 4.087 | 4.122
    Итого общее время было уменьшено с приблизительно 22 сек до 4 сек.

Кому то будет полезна информация о процессе инициализации окон в разделе и в окне редактирования (последовательность, наиболее ресурсоемкие операции):

Служба поддержки Террасофт пишет:
Процесс инициализации окон в разделе:
1. Десериализация – восстановление сохраненных объектов. Если раздел отображается впервые – происходит считывание данных из БД. Если раздел уже отображался – происходит считывание данных из Cache. В том случае, если системные характеристики компьютера достаточно низкие данная процедура будет происходит сравнительно медленно.
2. Инициализация групп, основного реестра, глобальных переменных, ссылок на наборы данных и открытие набора данных групп.
Отправной точкой для отображения данных является открытие набора данных групп с позиционированием на корневой группе (function OpenGroupsDataset()).
3. Вызов метода Show() для каждого элемента раздела.
4. Вызов метода Prepare() для каждого элемента раздела.
5. Фильтрация реестра записей.
6. Фильтрация текущего представления
7. Заполнение реестра данными
8. Refresh активной детали.

Процесс инициализации карточки редактирования:
1. Десериализация.
2. Вызов метода Show() окна.
3. Вызов метода Prepare() окна.

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

С функциями, используемыми при инициализации Вы можете ознакомиться в SDK.

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

Раловец Ольга пишет:
Пример реализации из проекта.
function wnd_MainOnShow(Window) {
    Self.BeginUpdate();
    var WspCodesArray = Main.UserSettingsWindow.Attributes('WorkspacesForCaching').split(' ');
    for (var i in WspCodesArray) {
        var WorkspaceWindowCode = WspCodesArray[i];
        if (IsEmptyValue(WorkspaceWindowCode)) {
            continue;
        }
        var WorkspaceWindow = GetWorkspaceByUSI(WorkspaceWindowCode);
        wndWorkspace.Window = WorkspaceWindow;
        var EditWindowUSI = '';
        if (Assigned(WorkspaceWindow.ComponentsByName('wndGridData'))) {
            EditWindowUSI =
                WorkspaceWindow.ComponentsByName('wndGridData').Window.Attributes('EditWindowUSI');
        }
        if(IsEmptyValue(EditWindowUSI)) {
            continue;
        }
        var Attrs = GetNewDictionary();
        AddRequiredValuesToDictionary(Attrs, GUID_NULL, false, true);
        var EditWindow = ShowEditWindowEx(EditWindowUSI, Attrs, System.EmptyValue, true, true);
        EditWindow.Close();
    }
    Self.EndUpdate();
}

В данном случае требовалось кэшировать при запуске системы разделы, отмеченные пользователем в настройках, и их карточки редактирования. Вместо строчки
var WspCodesArray = Main.UserSettingsWindow.Attributes('WorkspacesForCaching').split(' ');
можно явно указать нужные разделы, задав массив WspCodesArray, элементами которого являются коды главных окон этих разделов, например, 'wnd_ContactsWorkspace'. Если карточки редактирования Вас не интересуют, то все сведется к

function wnd_MainOnShow(Window) {
    //предварительная инициализация разделов
    Self.BeginUpdate();
    var OriginalWorkspaceWindow = wndWorkspace.Window;
    var WspCodesArray = new Array('wnd_AccountsWorkspace',
            'wnd_ContactsWorkspace', 'wnd_TasksWorkspace',
            'wnd_OpportunitiesWorkspace', 'wnd_ContractsWorkspace',
            'wnd_DocumentsWorkspace', 'wnd_InvoicesWorkspace',
            'wnd_MailWorkspace');
    for (var i in WspCodesArray) {
            var WorkspaceWindowCode = WspCodesArray[i];
            if (IsEmptyValue(WorkspaceWindowCode)) {
                    continue;
            }
            var WorkspaceWindow = GetWorkspaceByUSI(WorkspaceWindowCode);
            wndWorkspace.Window = WorkspaceWindow;        
    }
    wndWorkspace.Window = OriginalWorkspaceWindow;
    Self.EndUpdate();
}

Данная функция описана в скрипте scr_Main. Проект был реализован на базе версии 3.2.1.

Источник: как ускорить первоначальное открытие разделов
http://community.terrasoft.ua/forum/topic/4285

Нравится

Поделиться

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

Комментарий от партнера вендору: более чем ценная информация. для каждого из нас. не секрет, что темпы развития продуктов ТС опережают возможности документаторов и техподдержки ТС. Опережают они и наши возможности. Намного опережают. В ходе работы часто сталкиваемся с ситуацией когда надо перелопатить "единого слова ради тысячи тонн словесной руды" (форумы на Сообществе, документация к продуктам) и...все равно решения нет. Очень нужна публикация такого рода обобщенных наблюдений. в том числе от техподдержки ТС, когда вы, коллеги, отвечая по запросам, находите ответ или решение, не задокументированное ранее. Спасибо.

А еще ...
В базовой функции RefreshDetails все вставляют толпу if'ов и условия там идут вида: pgDetails.ActivePage.Name == pgMyDetail.Name
Для меня до сих пор, кстати, загадка зачем берут именно свойство объекта, а не строку )
это раз. а два - это ifы необходимо заменить на switch. В данном контексте switch работает быстрее. Конечно же это просто капля по сравнению со всем другим, но все-таки ;-)

Функция выводит список скриптов и функций, которые используются в указанном скрипте: перенес сюда.

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

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

утилита>.exe -? или утилита>.exe –h
Сегодня речь пойдет о TSExtractServices. Ее назначение – выгрузка сервисов конфигурации и загрузка обратно. При выгрузке конфигурации на выходе она создает 3 файла: Services.xml, Scripts.js, FastReport.xml.
Services.xml - по сути это xml-ники выгруженных сервисов, которые сложили в один файл.
Если xml-представление большинства сервисов не вызывает никаких проблем с пониманием, то с 2-мя типа сервисов ситуация иная. Это скрипты и отчеты. В Services.xml текст скрипта и содержимое отчета хранятся в бинарном виде. Именно поэтому в утилите реализована выгрузка в отдельные файлы всех скриптов и всех отчетов.
Scripts.js – содержит тексты всех выгруженных скриптов, т.е. в Services.xml содержится информация о сервисе скрипта, а в Scripts.js – текст самого скрипта.
FastReport.xml – ситуация аналогичная, с той лишь разницей, что отчеты складываются в файл тоже в xml-формате (у FastReport свое xml-представление отчетов, в котором сразу разобраться не так то просто, да и ни к чему наверное :) ).

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

-sd – отображать диалог с утилитой или нет. Допустимые значения true и false. Данный параметр (установленный в false) лучше всего использовать для автоматизации регулярной выгрузки или загрузки сервисов. При этом необходимо помнить, что если вы не указали какой либо параметр, то будет использовано его значение по-умолчанию (отображается в [] скобках в диалоговом режиме). Если же значения по-умолчанию у параметра нет, то утилита спросит его сама.

-c – название конфигурации (configuration).

-wa – использовать windows аутентификацию или нет для соединения с конфигурацией (варианты: true, false).

-u – имя пользователя для входа в конфигурацию.

-p – пароль.

-d – что делаем с сервисами – выгружаем из базы (unload) или загружаем в нее (load).

-st – параметр установленный в false, позволяет создавать сервисы таблиц в конфигурации без их физического создания в базе данных. Это может понадобится, например, в случае, когда сервисы таблиц находятся в стадии разработки и не могут быть физически сохранены в базе данных без ошибок. При использовании параметра –sd=false, по-умолчанию, сервисы таблиц не сохраняются.

-sr – сохранение внешних ключей. Параметр используется при загрузке сервисов. Внешние ключи по-умолчанию также не сохраняются, для их сохранения необходимо принудительно установить параметр в true. Внешние ключи бывает необходимым не сохранять в случаях, когда в таблицах нарушена ссылочная целостность данных.
В случае необходимости, вы всегда можете пересохранить свои таблицы с внешними ключами и индексами, использовав методы скрипта scr_ResaveTable.

-tc – типы сервисов (сокращение взялось от Service Type Code – код типа сервиса), в качестве кода типа сервиса могут быть указаны Table (таблица), DBDataset (набор данных) и др. Список кодов типов сервисов можно найти в файле CoreSettings.xml в разделе ServiceTypes. Пример для выгрузки всех сервисов перечислений и диаграмм процессов:

TSExtractServices –c=configuration –u= Supervisor –sd=false –tc=Enum; WorkflowDiagram
При таких параметрах получим выгруженные (значение по-умолчанию) сервисы перечислений и диаграмм процессов, соединение с конфигурацией будет осуществлено с использованием аутентификации на уровне базы данных (значение по-умолчанию).

-i – список модулей, из которых выгружаются сервисы (от слова include)
Если, к примеру, необходимо выгрузить все скрипты, которые расположены в модуле Common это можно сделать следующим образом

TSExtractServices –c=configuration –u=Supervisor –sd=false –tc=Script –i=Common

-pth – путь, где будут сохранены результирующие файлы. По-умолчанию это значение: Bin\ExtractServices\название конфигурации>.

-m – тип выгрузки/загрузки. Данный параметр может принимать значения services и database. Внутри это реализовано следующим образом: при использовании значения database у набора данных вызывается метод сохранения или загрузки значения blob-поля, в котором хранится сервис, в xml-файл. Если используется значение services, то при выгрузке сервисов, из blob-поля в таблице, будет создан объект сервиса, и только потом сервис будет сохранен в файл. Рекомендуется при выгрузке сервисов в файл использовать значение параметра services. При загрузке сервисов наоборот – database. Если при загрузке сервисов использовать параметр services, то это будет означать, что на основании загружаемых xml-ников будут создаваться объекты сервисов, причем не одновременно, а в порядке очереди, соответственно, если между сервисами есть ссылки (а вероятность этого 90%), то они могут сбросится в пустое значение и после загрузки мы получим неработающую конфигурацию.

Ну а напоследок хочется напомнить о параметрах -? и –h, которые покажут список всех остальных.

Нравится

Поделиться

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

В каких версиях есть данная утилита? конкретно интересует версия 3.0.2.66

Василий, Extract Services выпускается начиная с версии 3.0.2

В версии 3.0.2.66 данную утилиту не обнаружил. Подойдет ли утилита из других версий?

Запросите в support, Вам вышлют для версии 3.0.2

Запросите в support, Вам вышлют для версии 3.0.2

спасибо

Спасибо. Утилита помогает когда нет возможности использовать бэкапы.
Небольшая идея по усовершенствованию.

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