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

Желательно присутствие бывалых Одинов, которые повидали многое в данном продукте.

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



На данный момент были созданы на основе базовых схем, следующие схемы:

аналог FileUploadInfo,

аналог IFileUploadInfo,

KmFileUploadService - аналог сервиса FileApiService,

аналог FileUploader аналог.



Так же была заимствована логика подготовки и отправки файла до FileAPI из FileDetailV2 и ConfigurationFileApi.




При выборе некого файла (если помните ранее писал про кнопку Selec file, клик которой создает скрытый input с type = file и реализует клик по нему) после логики схем FileDetailV2 и ConfigurationFileApi файл попадает в FileAPI, где на мой взгляд происходит его подготовка и разбиение на Chunk (далее Чанки).

После всех манипуляций дынный Api посылает его в KmFileUploadService
 , который вызывает унаследованный FileUploader, конкретно метод Upload, где происходит проверка размера файла, а далее ведется проверка связанная с Чанками (!fileUploadInfo.IsChunkedUpload || fileUploadInfo.IsFirstChunk) и в зависимости от проверки запускается метод Save или AppendData.



Как только текущий Чанк попадает в Save, исходя из нашей логики я организовываю запросы на Ftp по созданию файла (ничего такого, чего нет на MSDN).

Далее как я понимаю идёт обратный запрос к FileAPI который в свою очередь отдает нам следующий Чанк, который попадает в AppendData.



Базовая реализация этого метода подразумевает вызов метода DBLobUtilities.AppendBlob.

В нашем случае мы не используем этот метод, так как сохранение файла в базу у нас не велось. Мы используем аналогичный подход как в нашем Save только указываем WebRequestMethods.Ftp.AppendFile ,который должен нам исходя из следующего Чанка дописать ранее созданный экземпляр файла. По завершению этого действия по идее должен быть обратный ответ от FileAPI, который вышлет нам следующий Чанк и так далее пока все Чанки не кончатся, но этого не происходит. См. приложенный скриншот.

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



Итак самое главное вопросы:

1. Не удалось найти реализацию базового метода DBLobUtilities.AppendBlob, т.е. что он выполняет и каким образом запросы к FileAPI не прерываются. Потому что в нашем случае весь процесс состоит из двух Чанков, + второй Чанк сильно переписывает и ломает тело файла.

2. Хотелось бы узнать существует ли возможность в наш сервис передать кастомное значение типа пункта назначения фолдера, куда сохранять файл. Есть подозрения что нужно будет расширить FileUploadInfo и интерфейс который он использует, и обязательно расширить UI методы который формируют объект для FileAPI.

 

P.s. если не использовать данный подход, а работать с обыкновенным FileReader и читать тело файла readAsDataURL то всё бы ничего, но вот если файл весит свыше 10мб у сервиса начинается батхерт со временем обработки запроса.

Нравится

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

Не понимаю зачем зарывать в такие дебри. У меня сработало так:

1) Создал миксин, обрабатывающий  клик и загрузку.

define("TmUploadMixin", ["MaskHelper", "ConfigurationFileApi"],
	function(MaskHelper) {
 
		Ext.define("Terrasoft.configuration.mixins.TmUploadMixin", {
		alternateClassName: "Terrasoft.TmUploadMixin",
 
		/**FILE_IMPORTER**/
		onFilesSelected: function(file, tag) {
			if (file.length <= 0) {
				return;
			}
			var config = this.getUploadConfig(file, tag);
			this.upload(config);
		},
		getUploadConfig: function(file, tag) {
			return {
				uploadWebServicePath: "TmFilesUploader/Upload", // "FileApiService/Upload"
				scope: this,
				columnName: "columnName",
				parentColumnName: "parentColumnName",
				parentColumnValue: "parentColumnValue",
				onFileComplete: this.onFileComplete,
				entitySchemaName: tag,
				files: file,
				isChunkedUpload: false
			};
		},
		upload: function(config) {
			MaskHelper.ShowBodyMask();
			Terrasoft.ConfigurationFileApi.upload(config);
		},
		onFileComplete: function(error, xhr, file, options) {
			MaskHelper.HideBodyMask();
			//debugger;
			var data = JSON.parse(Terrasoft.decode(xhr.responseText));
			if (data.error !== "False") {
				this.showInformationDialog("Ошибка импорта. Подробнее — в консоли");
				console.log(data.data);
			} else {
				this.showInformationDialog("Записей импортировано: "+data.data);
				//this.reloadGridData();
			}
		}
 
	});
	return Terrasoft.TmUploadMixin;
});

 

2) Создал сервис

namespace Terrasoft.Configuration.TmFilesUploader
{
	using System;
	using System.IO;
	using System.Net;
	using System.Data;
	using System.Runtime;
	using System.Collections.Generic;
	using System.Runtime.Serialization;
	using System.ServiceModel;
	using System.ServiceModel.Web;
	using System.ServiceModel.Activation;
	using System.Web;
	using System.Web.SessionState;
	using Terrasoft.Common;
	using Terrasoft.Core;
	using Terrasoft.Core.Factories;
	using Terrasoft.Core.Entities;
	using Terrasoft.Configuration.FileUpload;
	using Terrasoft.Web.Common;
 
 
	[ServiceContract]
	[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
	public class TmFilesUploader : BaseService, IReadOnlySessionState
	{
		[Obsolete]
		public const string HeaderContentRange = "Content-Range";
		[Obsolete]
		public const string HeaderRange = "Range";
		[Obsolete]
		public const string HeaderContentDisposition = "Content-Disposition";
 
		[OperationContract]
		[WebInvoke(Method = "POST", UriTemplate = "Upload", ResponseFormat = WebMessageFormat.Json)]
		public string Upload(Stream fileContent) {
			string value;
			bool error=false;
			try {
				IFileUploadInfo fileUploadInfo = new FileUploadInfo(fileContent, new HttpRequestWrapper(HttpContext.Current.Request);
				/**стрим будет валяться в fileUploadInfo.Content**/
			} catch (Exception ex) {
				value = ex.Message+"|"+ex.Source+"|"+ex.StackTrace+"|"+ex.InnerException;
				error = true;
			}
 
			return "{\"error\":\"" + error + "\",\"data\":\"" + value + "\"}";
		}
	}
}

И как бы всё... Ну единственно отрубил chunkedUpload и оставил дефолтный террасофтовский метод по проверке веса файла (думаю можно отредактировать если надо)

Варфоломеев Данила пишет:

Варфоломеев Данила

Добрый день/ночь, вот что получаем в итоге при ~20+ мб весом файла, ограничение Террасофта в настройке повысил. Понимаю что файл надо разбить каким-то образом на осмысленные части и грубо говоря из сервиса append'ить эти части между собой. Но мысли пока зашли в тупик.

Есть предположения у Вас коллега? 

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

Добрый день!

Подскажите, как отключить уведомления о знаменательных событиях для всех пользователей bpm online SE 7.10 . Нигде в документации и в сообществе не нашел информации, как это сделать.

Нравится

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

Зайдите в конфигуратор, найдите БП с названием 'Generateanniversaryremindings’. Его надо отредактировать, добавив ему тэг ‘Business process’. После этого сохраняете, публикуете и выставляете версию как актуальную. После этого процесс будет виден в списке Process Library и его можно будет деактивировать. После всех манипуляций рекомендуется очистить кэш браузера.

Спасибо, помогло!

you are welcome

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

Добрый день!

 

разработали пакет на bundle , пакет зависит от ServiceEnterprise и от SalesEnterprise.

нужно перенести в среду, где только Sales. в нашем пакете есть две замещающие схемы CasePage, CaseSection, но они нам не нужны.

я удалила эти схемы, убрала зависимость от ServiceEnterprise  и тут все сломалось: в созданных вручную объектах "слетел" родительский объект(базовый объект) и валится ошибка:Элемент коллекции с идентификатором "{AE0E45CA-C495-4FE7-A39D-3AB7278E1617}" не найден

 

есть ли способ корректно отвязывать зависимости от пакета?

Нравится

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

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

Максим Цынгаев,

ошибка выходит как раз при генерации кода. не удается провести генерацию из-за ошибки "

Элемент коллекции с идентификатором "{AE0E45CA-C495-4FE7-A39D-3AB7278E1617}" не найден"

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

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

Внешний web.config

1.    

   - удалить провайдеры SsoAuthProvider, SSPSsoAuthProvider

   

2.     

    - заменить https на http

       

    - заменить https на http

    

3.

    

         

     

   


   - удалить секцию ?use_sso=true

   

4.

    

   


   - установить use_sso=false

   - установить requireSSL="false

5.  

    - удалить атрибут requireSSL

    

Внутренний web.config

1.

    - установить value=false

2.

    - изменить значение на false

3.

    - Удалить атрибут requireSSL

    

4.

    - Изменить https на http

5. После того, как вы «вошли в систему», т.е. после логина – перейдите в конфигурацию по Url: http://[сайт]/[приложение]/dev

6. Cкомпилировать всю конфигурацию.

Нравится

Поделиться

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

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

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



Как программно ограничить возможные результаты активности ?

Можно ли для этого использовать поле AllowedResult объекта Активность и если да, то как его формировать?

Нравится

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

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

Единственная сложность - это привести в компании все активности к одним стандартам

Спасибо. Похоже, это самый легкий путь.

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

Тёскин Дмитрий Валерьевич пишет:

Если делать через "Добавить задачу"

Если вы немного модифицируете объект "Активности", то через "Добавить задачу" уже мало можете сделать 

Вот сравнения двух подходов:

https://community.terrasoft.ua/questions/vypolnit-zadacu-i-dobavit-dann…



И советы по расширению "Выполнить задачу": https://community.terrasoft.ua/questions/element-biznes-processa-vypoln…

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

 

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

Имеется код, который может запускаться при помощи планировщика.В коде есть строка, в которой получается адреса сайта. При запуске из планировщика будет возникать NullReferenceException, по всей видимости, HttpContext.Current - null.

var applicationUrl = Terrasoft.Web.Common.WebUtilities.GetParentApplicationUrl(
                HttpContext.Current.Request);

Какой есть ещё способ получить адрес сайта?

Нравится

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

Как вариант, можно использовать системную настройку SiteUrl 

protected virtual string GetApplicationUrl() {
	string urlString = HttpContext.Current != null
		? WebUtilities.GetBaseApplicationUrl(HttpContext.Current.Request)
		: SystemSettings.GetValue(this._userConnection, "SiteUrl", string.Empty);
	return urlString;
}

 

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

Добрый день.

Такое впечатление что ошибка очень простая но не понимаю где она. Код:

define("OpportunityPageV2", ["BusinessRuleModule"], function(BusinessRuleModule) {

    return {

        entitySchemaName: "Opportunity",

        attributes: {

                "OpportunityId1": {

                    "dataValueType": Terrasoft.DataValueType.TEXT,

                    "type": Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN,

                    "value": ""

                }

            },

        details: /**SCHEMA_DETAILS*/{}/**SCHEMA_DETAILS*/,

        diff: /**SCHEMA_DIFF*/[]/**SCHEMA_DIFF*/,

        methods: {

            init: function() {

                    this.callParent(arguments);

                    this.initMeetingId();

                },

                // Метод определения идентификатора категории активности.

                initMeetingId: function() {

                    var SaleId = this.get("Id");

...............................

в SaleId при этом получается undefined....

Помогите найти ошибку.

Нравится

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

Добрый день всем.

При попытке обращения к сервису через Js возникает 500 ошибка.

Пример объявления метода Сервиса:

[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "Upload", BodyStyle = WebMessageBodyStyle.Wrapped,
RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
   public string Upload(Stream fileContent, string fileName, string fileDestination) {

 

Пример вызова из Js:

var file = files[0];
    var reader = new FileReader();
    reader.readAsBinaryString(file);
    reader.addEventListener("load",
         function(item) {
	 var data = {
       	      fileContent: item.target.result,
	      fileName: file.name,
	      fileDestination: destinationPath
	 };
	 ServiceHelper.callService("KmFileUploadService",
	      "Upload",
     	      function(response) {
	           this.console.log(response);
	      },
	      data,
	      this
	 );
	 }.bind(this),
    false);

Кто знает, в чём конкретно может быть проблема? При попытках вызова сервиса (когда у метода всего 1 параметр) не возникает никаких проблем.

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

Нравится

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

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

https://stackoverflow.com/questions/7999634/parsing-a-stream-and-a-para

 Хм, повторюсь. Я брал пример с исходников. Если там всё работает исправно то и в моем случае должно отрабатывать как часы. Тип роли не играет. Хоть 3 стринга там указать всё равно будет 500 ошибка.

Кисловский Михаил Андреевич,

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

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

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

На деталь Средства связи контакта добавили запреты на использование:

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

Запреты должны быть связаны со стандартными колонками Контакта DoNotUseEmail, DoNotUseCall и так далее. Их тоже вывели на страницу:

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

Далее подключил синхронизацию по схеме: https://community.terrasoft.ru/questions/sinhronizacia-kolonok-kartocki…

В атрибуты ContactPageV2 добавил вызов метода syncEntityWithCommunicationDetail, переопределил ContactCommunicationDetail, где в initMasterDetailColumnMapping добавил новые типы:

//Запреты на использование
						{
							"CommunicationType": "105728d2-d097-4dea-94be-713cd9c6f38c",
							"MasterEntityColumn": "DoNotUseEmail"
						},
						{
							"CommunicationType": "b6e11e60-8ce5-46d7-a7e9-1a356d762263",
							"MasterEntityColumn": "DoNotUseCall"
						},
						{
							"CommunicationType": "476feae6-8162-4997-904e-447a6d916371",
							"MasterEntityColumn": "DoNotUseFax"
						},
						{
							"CommunicationType": "1dc8b3d6-1028-4524-b3d8-8e05663b3bb3",
							"MasterEntityColumn": "DoNotUseSms"
						},
						{
							"CommunicationType": "71b3e7ae-efaf-474e-a76a-82d13ef376b0",
							"MasterEntityColumn": "DoNotUseMail"
						},

Проблема 1:

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

Проблема 2 (возможно, проблема 1 следует из неё):

Синхронизация, даже если она работает,то  происходит не сразу. Чтобы изменения были видны, мне нужно сохранить страницу, выйти из неё и зайти заново.

Как правильно сделать синхронизацию для чекбоксов?

Нравится

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

В процессе изучения проблемы заметил, что id у пунктов из списка запретов (см. скриншот) меняются при каждой перезагрузке страницы, а в объектах BaseCommunication, ContactCommunication записей, как-то связанных с чекбоксами нет вовсе.

Добрый день, Денис.

Метод syncEntityWithCommunicationDetail не связан с кнопками "не использовать" на детали средства связи, поскольку работает с абсолютно другой коллекцией детали. Вам стоит смотреть в сторону создания своих сообщений sandbox для работы с методом doNotUseCommunication, который добавляет элемент в коллекцию RestrictionsCollection детали. Также обратите внимание на метод getRestrictionsItemConfig, который создает конфиг для каждой кнопки, связанной с запретом на использование.

>> Синхронизация, даже если она работает,то происходит не сразу

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

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

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

Я из бизнес-процесса отправляю email по шаблону. Шаблон в справочник добавила. В шаблон передаю Id обращения и в конечном итоге на почту получаю письмо, которое в себе содержит определенные данные обращения (номер, ответственный, контакт\контрагент и тд).

Подскажите, а могу ли я как-то в шаблон отправить данные с детали (например, Жизненный цикл обращения)?

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

Здравствуйте, Елена!

В текущей реализации приложения bpm'online нет возможности вывести в шаблон значение из связанного объекта (детали) или агрегирующие значения. Я зафиксировал и передал Ваше пожелание аналитикам продукта. Они рассмотрят возможность реализации в будущих версиях программного продукта.

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