Добрый день. Есть созданый нами сервис (по образцу базового ReportService), который возвращает по записи детали объекта pdf-файл. На десктопной версии креатио работа с ним настроена, возникли сложности с реализацией аналогичного в мобильном приложении.

По подробностям: на десктопе сервис на странице записи детали по нажатию кнопки получает значение поля и в ответ открывает файл на новой странице. Как именно что-то подобное сделать для записей детали на мобильном приложении? Есть ли какие-то нюансы с открытием pdf в мобильном приложении креатио?

Нравится

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

Добрый день!

 

Позвольте привести пример скачивания и автоматического открытия файла с использованием базового FileService/GetFile (сервис и метод, которые триггерятся если в декстопной версии из детали с файлами выгрузить какой-либо файл) в мобильном приложении. Для этого:

1) Была создана кастомная кнопка в действиях на странице контакта в мобильном приложении

2) Был создан обработчик для нажатия на эту кнопку

Как это было достигнуто:

1) В конфигурации создать модуль UsrMyAction с кодом

Ext.define("Terrasoft.MyAction", {
	extend: "Terrasoft.ActionBase",
	config: {
		useMask: false,
		title: "MyActionTitle",
		iconCls: Terrasoft.ActionIcons.Copy
	},
 
	execute: function(record) {
		this.callParent(arguments);
		var config = {
			url: 'https://1168222internal-demo.creatio.com/0/rest/FileService/GetFile/e9eafee9-c4e4-4793-ad0a-003bd2c6a9b4/3bbbd5a8-8f8d-4570-8526-0488eb37da28',
			success: function(fullPath, relativePath) {
				Terrasoft.FileIntent.open({
					path: relativePath
				});
			}, 
			name: "Test_" + new Date().toDateString() + ".png"
		};
 
		Terrasoft.RequestManager.issueRequest({
					requestFn: Terrasoft.FileTransfer.download,
					requestFnConfig: config,
					responseToStatusCodeFn: Terrasoft.FileTransfer.getStatusCodeFromException,
					loginFailure: function(exception) {
						Ext.callback(config.failure, config.scope, [exception]);
					},
					suppressRequestEvents: config.suppressRequestEvents,
					scope: Terrasoft.FileTransfer
				});
		this.executionEnd(true);
	}
 
});

 

В нем создать локал.строку с кодом MyActionTitle и каким-то значением для этой локал.строки (например "Call custom service").

2) В конфигурации создать модуль UsrMobileContactModuleConfig с кодом

Terrasoft.sdk.Actions.add("Contact", {
    name: "myAction",
    actionClassName: "Terrasoft.MyAction"
});



3) В манифесте мобильного приложения добавить:

"CustomSchemas": [

"UsrMyAction"

],

...

"Models": {

...

"Contact": {

...

"PagesExtensions": [

"UsrMobileContactModuleConfig"

]

Пример манифеста из демо сайта для тестов, где тестировалась логика – файл MobileApplicationManifestDefaultWorkplace.txt ниже:

{
	"CustomSchemas": [
        "UsrMyAction"
    ],
	"SyncOptions": {
		"SysSettingsImportConfig": [
			"DefaultMessageLanguage"
		],
		"ModelDataImportConfig": [
			{
				"Name": "Contact",
				"SyncColumns": []
			},
			{
				"Name": "SysLanguage",
				"SyncColumns": []
			},
			{
				"Name": "ContactFile",
				"SyncColumns": [
					"Contact",
					"CreatedOn",
					"CreatedBy",
					"Name",
					"Data",
					"Type",
					"Size"
				]
			},
			{
				"Name": "FileGroup",
				"SyncColumns": []
			},
			{
				"Name": "ContactCommunication",
				"SyncColumns": [
					"CommunicationType",
					"Number",
					"Contact"
				]
			},
			{
				"Name": "CommunicationType",
				"SyncColumns": []
			},
			{
				"Name": "ContactAddress",
				"SyncColumns": [
					"AddressType",
					"Country",
					"Region",
					"City",
					"Address",
					"Zip",
					"Contact"
				]
			},
			{
				"Name": "AddressType",
				"SyncColumns": []
			},
			{
				"Name": "Country",
				"SyncColumns": []
			},
			{
				"Name": "Region",
				"SyncColumns": []
			},
			{
				"Name": "City",
				"SyncColumns": []
			},
			{
				"Name": "ContactAnniversary",
				"SyncColumns": [
					"Date",
					"AnniversaryType",
					"Contact"
				]
			},
			{
				"Name": "AnniversaryType",
				"SyncColumns": []
			},
			{
				"Name": "FileType",
				"SyncColumns": []
			},
			{
				"Name": "SocialMessage",
				"SyncColumns": [
					"EntityId"
				]
			}
		]
	},
 
	"Modules": {},
	"Models": {
		"ContactFile": {
			"RequiredModels": [
				"ContactFile",
				"FileGroup",
				"SocialMessage"
			],
			"ModelExtensions": [],
			"PagesExtensions": [
				"UsrMobileContactFileActionsSettingsDefaultWorkplace",
				"UsrMobileContactFileGridPageSettingsDefaultWorkplace",
				"UsrMobileContactFileRecordPageSettingsDefaultWorkplace"
			]
		},
		"SocialMessage": {
			"RequiredModels": [],
			"ModelExtensions": [],
			"PagesExtensions": []
		},
		"Contact": {
			"RequiredModels": [
				"Contact",
				"SysLanguage",
				"ContactFile",
				"FileGroup",
				"ContactCommunication",
				"CommunicationType",
				"ContactAddress",
				"AddressType",
				"Country",
				"Region",
				"City",
				"ContactAnniversary",
				"AnniversaryType",
				"FileType"
			],
			"ModelExtensions": [],
			"PagesExtensions": [
				"UsrMobileContactModuleConfig"
			]
		}
	},
	"ModuleGroups": {
		"main": {}
	},
	"UseUTC": true
}



4) Обязательно выполнить рисайкл пула приложения (не перезапуск сайта в IIS, а именно рисайкл пула).

Сама логика скачивания файла и его открытие реализована в модуле UsrMyAction:

var config = {

url: 'https://1168222internal-demo.creatio.com/0/rest/FileService/GetFile/e9e…

success: function(fullPath, relativePath) {

Terrasoft.FileIntent.open({

path: relativePath

});

},

name: "Test_" + new Date().toDateString() + ".png"

};

Terrasoft.RequestManager.issueRequest({

requestFn: Terrasoft.FileTransfer.download,

requestFnConfig: config,

responseToStatusCodeFn: Terrasoft.FileTransfer.getStatusCodeFromException,

loginFailure: function(exception) {

Ext.callback(config.failure, config.scope, [exception]);

},

suppressRequestEvents: config.suppressRequestEvents,

scope: Terrasoft.FileTransfer

});

Какие здесь ключевые моменты:

1) https://1168222internal-demo.creatio.com/0/rest/FileService/GetFile/e9e… получить файл (кстати, здесь можно немного заменить код на следующий:

var config = {

url: Terrasoft.CurrentUserInfo.serverUrl + '0/rest/FileService/GetFile/e9eafee9-c4e4-4793-ad0a-003bd2c6a9b4/3bbbd5a8-8f8d-4570-8526-0488

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

2) "Test_" + new Date().toDateString() + ".png" - это название файла, который будет подгружен и автоматически открыт. Здесь важно еще контролировать расширение скачиваемого файла, но если в 100% случаев будет скачиваться PDF, то можно здесь просто захардкодировать расширение .pdf.

3) За подгрузку файла отвечает метод Terrasoft.RequestManager.issueRequest, в который мы передаем в config ссылку откуда нам нужно получить файл и что делать в случае успешного выполнения метода issueRequest (здесь можно добавить и failure обработчик).

4) На success п.3 запускается метод Terrasoft.FileIntent.open который и отвечает за автоматическое открытие файла.

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

Ограничение: сервис по получению файла должен быть доступен через метод GET. Если сейчас у Вас он реализован через POST, то создайте рядом еще один метод специально для мобильного приложения и вызывайте в коде его (в URL вызова можно передавать значение аргументов для метода (например, ID записей файлов или т.д.)).

Что нужно заменить:

1) Кастомную кнопку с действием я добавлял на карточку контакта. Вы же можете ее добавить в карту детали с файлами (подход тот же, только вместо Contact – название объекта детали). Ну или можете динамически вычитывать записи из детали и выбирать подходящую.

2) Продумать как реализовать названия файлов (опять же, можно считывать оригинальный файл из детали, брать его название и вставлять в параметр name).

Результат (тестировал и на iOS физическом девайсе и в эмуляторе в Android studio):

1) Сама кнопка:

 

2) Нажатие на кнопку:

 

Далее файл можно сохранить:

 

 

потестируйте и продолжайте кастомизировать под Ваш сервис.

 

 

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

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

 

Вопрос скорее к Террасофт. Скажите, а почему убрали возможность выгрузки печатной формы в pdf? Чем продиктовано такое решение? Было очень удобно формировать счета, например.

Нравится

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

Добрый вечер.

 

Мне служба поддержки ответила следующее: 

Начиная с версии 7.14.2 из продукта исключена возможность выгрузки печатных форм в формате PDF.

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

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

Добрый вечер.

 

Мне служба поддержки ответила следующее: 

Начиная с версии 7.14.2 из продукта исключена возможность выгрузки печатных форм в формате PDF.

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

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

 

 

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

Мда, понять бы какие именно будущие версии подразумеваются. со времен 7.14 достаточно много времени прошло( А пользователям-то вынь, да положь)

 

Сидоров Александр Валерьевич пишет:

со времен 7.14 достаточно много времени прошло

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

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

fastreport же всегда был. Ну и использовать его для формирования счета - странная идея на мой взгляд. Был простой и понятный инструмент. Зачем тратить силы на то, чтобы его выпилить?)

Сидоров Александр Валерьевич пишет:

fastreport же всегда был.

Только в 3.Х. 

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

 

Я думаю, что Александр Сидоров имеет ввиду, что механизм настройки отчета в Word в разы проще, чем в FastReport.

 

Опять таки очень мало информации с различными примерами о том, как настраивать отчет в FastReport.

Сидоров Александр Валерьевич,

Это все, чтоб жизнь малиной не казалась)))

Алла, вероятно, всё дело в ограничениях на сторонние компоненты, вроде того же Aspose.

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

да, с fastreport она точно не шоколад)

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

 

Также в маркете есть несколько других движков печатных форм, в том числе есть и PDF Generator connector, интегрирующийся со сторонней платформой.

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

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

Сидоров Александр Валерьевич,

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

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

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

Часто стоит именно такая задача, чтобы сразу выгружать в pdf, особенно касается документов с подписями и печатями (чтобы не вносились изменения пользователем непосредственно в документе).

 

Ну, и странно то, что был бесплатный базовый функционал, который это делал, а сейчас ты предлагаешь платную утилиту(

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

а я, честно говоря, и не помню. Разработчики как-то делали, я не вникал в детали. Но это было давно, еще в 7.12 или около того

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

бесплатный базовый функционал

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

Aspose - американская компания, Террасофт - российская, чтобы быть ближе к полностью российской перевели библиотеки на российские. FastReport - российская

Всё оказалось проще, но за отдельную плату (от 99$).

Информация от devlabs:

Мы выпустили маркетплейс пакет, который позволит клиентам конвертировать ПФ в PDF:

Aspose.PDF connector for Creatio

Клиентам с версии 7.16.1 и новым справочником ПФ, кому нужна печать файлов в PDF, можно смело рекомендовать установить пакет.

Сам пакет бесплатный, но использование сервиса конвертации стоит денег. Цены перечислены тут: https://purchase.aspose.cloud/pricing + есть бесплатный триал.

Руслан Хасанов, Украинская компания, просто офис продаж есть в России

Александр Тыра,

Может быть. Я смотрел здесь - 

https://reestr.minsvyaz.ru/request/165716/?sphrase_id=446874

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

Проблема всех таких облачных третьих решений - это отсылка своих данных неизвестно куда. 



Не все клиенты могут себе это позволить, потому хочется иметь инструмент для генерации pdf 100% on-site



И сюда же Preview приложенных файлов (pdf хотя бы) 100% on-site

Владимир, в настоящее время стандартный в системе механизм отчётов FastReport генерирует их в пределах сайта. Вы можете включить в настройках тестовый отчёт «Знаменательные события контакта (пример)» и сгенерировать pdf-файл для любого контакта.

По высказанным в теме предложениям уже есть идеи: о необходимости функции конвертации word в pdf в продукте, о предпросмотре для файлов тех форматов, для которых его ещё нет (pdf, doc, xls, tiff, ...) и заодно о предпросмотре печатных форм в FastReport.

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

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

Возможности:

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

 

Установить и попробовать можно по ссылке на маркетплейс

Более детально ознакомиться с возможностями можно по ссылке

Нравится

Поделиться

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

Пользователь нажимает кнопку/действие - идет вызов Исходного кода. Там вылолняется работа и возвращает MemoryStream(это файл ПДФ)

Как теперь сделать чтобы этот файл или скачался или отобразился в новой странице?

Нравится

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

Как то так:

var response = System.Web.HttpContext.Current.Response;
	response.ClearContent();
	response.ContentType = "application/pdf";
	response.AddHeader("Content-Disposition", "inline; filename=" + docName);
	response.AddHeader("Content-Length", docStream.Size);
	response.BinaryWrite((byte[])docStream);
	response.End();

 

Как то так:

var response = System.Web.HttpContext.Current.Response;
	response.ClearContent();
	response.ContentType = "application/pdf";
	response.AddHeader("Content-Disposition", "inline; filename=" + docName);
	response.AddHeader("Content-Length", docStream.Size);
	response.BinaryWrite((byte[])docStream);
	response.End();

 

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

Благодарю, вот в итоге рабочий код:

var response = System.Web.HttpContext.Current.Response;
response.ClearContent();
response.ContentType = "application/pdf";
response.AddHeader("Content-Disposition", "inline; filename=Ведомость расчетов с клиентом.pdf");
response.AddHeader("Content-Length", f.GetLongLength(0).ToString());
response.BinaryWrite(f);
response.End();

f - это тип byte[]

Рад что у вас получилось smiley

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

Добрый день, у нас в црм есть раздел “сделки”, куда попадают анкеты с формы на сайте, также вся эта форма преобразовывается в pdf и с помощью odata прикрепляется к той же сделке в црм в "файлы и примечания".
Подскажите, пожалуйста, можно ли как-то реализовать, чтобы в случае изменения полей сделки менеджером в црм полностью пересоздавался/изменялся фал pdf с новыми параметрами или же можно как-то из бизнес-процессов вызвать php скрипт для создания pdf, передавая необходимый id?

Нравится

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

Здравствуйте, Мария!

В bpm'online можно реализовать процесс, который будет запускаться по изменению записи. Однако логику изменения/создания *.pdf файла необходимо будет реализовать на C#.

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

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

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

В системе напрямую такой возможности нет, можно попробовать переопределить эту логику и добавить модулю архиватора на Javascript или С#, например https://habrahabr.ru/post/133129/

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

Подскажите пожалуйста, как можно реализовать передачу PDF документа в "файлы и примечания" раздела по протоколу OData с использованием Http-запросов?

Нравится

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

Добрый день.

Для хранения файлов и ссылок по каждому разделу есть отдельная таблица. Например, для раздела [Обращения] - это CaseFile.
Для загрузки файлов используется сервис FileApiService (метод Upload).
Пример вызова сервиса можно посмотреть на примере детали "Файлы и ссылки" (FileDetailV2).

Добрый день, спасибо за быстрый отклик.
Но как я понимаю FileApiService можно использовать для обработки события upload в самой crm. А задача состояла в обратном: на сайте генерируется pdf файл и необходимо его передать в карточку договора в файлы и примечания.
Разобралась как это сделать с помощью OData. Необходимо сначала создать файл, к примеру в ContractFileCollection, с помощью POST с привязкой к Id договора и с необходимым типом, а потом уже в созданный Id документа в /Data записывать необходимый файл с помощью запроса PUT с Content-Type: application/octet-stream.

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

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

Такая ситуация, есть обычная страница редактирования (PortalKnowledgeBasePage), а на ней обычная деталь (FileDetail), я хочу сделать так что бы при открытии страницы, сразу скачивался первый попавшийся файл на детали. На рендере страницы я вызываю этот метод:

renderDownloadFile: function () {
        var esqKnowledgeBaseFile = Ext.create("Terrasoft.EntitySchemaQuery", {
                "rootSchemaName": "KnowledgeBaseFile"
        });
        esqKnowledgeBaseFile.addColumn("Id");
        esqKnowledgeBaseFile.addColumn("KnowledgeBase");
        esqKnowledgeBaseFile.addColumn("Name");
        esqKnowledgeBaseFile.addColumn("Data");
        esqKnowledgeBaseFile.filters.addItem(Terrasoft.createColumnFilterWithParameter(
                Terrasoft.ComparisonType.EQUAL, "KnowledgeBase", this.get("PrimaryColumnValue")));
        esqKnowledgeBaseFile.getEntityCollection(function(resultKnowledgeBaseFile) {
                if (resultKnowledgeBaseFile.success) {
                        var textFileAsBlob = new Blob([resultKnowledgeBaseFile.collection.getByIndex(0).get("Data")], {type:'application/pdf'});
                        var fileNameToSaveAs = resultKnowledgeBaseFile.collection.getByIndex(0).get("Name");

                        var downloadLink = document.createElement("a");
                        downloadLink.download = fileNameToSaveAs;
                        downloadLink.innerHTML = "Download File";
                        if (window.webkitURL != null) {
                                downloadLink.href = window.webkitURL.createObjectURL(textFileAsBlob);
                        } else {
                                downloadLink.href = window.URL.createObjectURL(textFileAsBlob);
                                downloadLink.onclick = destroyClickedElement;
                                downloadLink.style.display = "none";
                                document.body.appendChild(downloadLink);
                        }
                        downloadLink.click();
                }
        }, this);
},

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

Нравится

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

Роман, проблема заключается в том что вы передаете в Blob стринг, вследствие чего файл получает нужный размер и тип, но абсолютно неправильное содержание. Работать массивами байтов в JavaScript не самая лучшая идея. Рекомендую Вам написать свой WCF сервис, который будет принимать Id записи, обращаться к базе данных и получать byte[]. Данный массив необходимо обвернуть в Stream и вернуть из сервиса добавив необходимый mime type.

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

"Мотков Илья" написал:Роман, проблема заключается в том что вы передаете в Blob стринг, вследствие чего файл получает нужный размер и тип, но абсолютно неправильное содержание. Работать массивами байтов в JavaScript не самая лучшая идея. Рекомендую Вам написать свой WCF сервис, который будет принимать Id записи, обращаться к базе данных и получать byte[]. Данный массив необходимо обвернуть в Stream и вернуть из сервиса добавив необходимый mime type.

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


Сделал как вы сказали, и все ровно не получается. Теперь клиентская сторона выглядит вот так:

onGetServiceInfoClick: function(idKnowledgeBase) {
				var serviceData = {
					KnowledgeBaseID: this.get("PrimaryColumnValue")
				};
				ServiceHelper.callService("CustomConfigurationService", "GetTransformValue",
				function(response) {
					var result = response.GetTransformValueResult;
					this.renderDownloadFile(result);
				}, serviceData, this);
			},
 
			renderDownloadFile: function (data) {
				var esqKnowledgeBaseFile = Ext.create("Terrasoft.EntitySchemaQuery", {
					"rootSchemaName": "KnowledgeBaseFile"
				});
				esqKnowledgeBaseFile.addColumn("Id");
				esqKnowledgeBaseFile.addColumn("KnowledgeBase");
				esqKnowledgeBaseFile.addColumn("Name");
				esqKnowledgeBaseFile.filters.addItem(Terrasoft.createColumnFilterWithParameter(
					Terrasoft.ComparisonType.EQUAL, "KnowledgeBase", this.get("PrimaryColumnValue")));
				esqKnowledgeBaseFile.getEntityCollection(function(resultKnowledgeBaseFile) { 
					if (resultKnowledgeBaseFile.success) {
						var textFileAsBlob = new Blob([data], {type:'application/pdf'});
						var fileNameToSaveAs = resultKnowledgeBaseFile.collection.getByIndex(0).get("Name");
 
						var downloadLink = document.createElement("a");
						downloadLink.download = fileNameToSaveAs;
						downloadLink.innerHTML = "Download File";
						if (window.webkitURL != null) {
							downloadLink.href = window.webkitURL.createObjectURL(textFileAsBlob);
						} else {
							downloadLink.href = window.URL.createObjectURL(textFileAsBlob);
							downloadLink.onclick = destroyClickedElement;
							downloadLink.style.display = "none";
							document.body.appendChild(downloadLink);
						}
						downloadLink.click();
					}
				}, this);
			},

А сам веб сервис вот так:

public class CustomConfigurationService
    {
        [OperationContract]
        [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped,
        ResponseFormat = WebMessageFormat.Json)]
        public MemoryStream GetTransformValue(string KnowledgeBaseID)
        {
            var UserConnection = (UserConnection)HttpContext.Current.Session["UserConnection"];
            var KnowledgeBaseFileESQ = new EntitySchemaQuery(UserConnection.EntitySchemaManager, "KnowledgeBaseFile");
            KnowledgeBaseFileESQ.AddAllSchemaColumns();
            var KnowledgeBaseIDFilter = KnowledgeBaseFileESQ.CreateFilterWithParameters(FilterComparisonType.Equal, "KnowledgeBase", new Guid(KnowledgeBaseID));
            KnowledgeBaseFileESQ.Filters.Add(KnowledgeBaseIDFilter);
            var KnowledgeBaseFileEnteties = KnowledgeBaseFileESQ.GetEntityCollection(UserConnection);
 
            var data = KnowledgeBaseFileEnteties[0].GetColumnValue("Data") as byte[];
            var result = new MemoryStream(data);
 
            return result;
        }
    }

Ну и в последнем методе "renderDownloadFile", параметр data вот такой

И ещё пробовал с веб сервиса передать массив байтов, и принимать его вот так:

var textFileAsBlob = new Blob(data, {type:'application/pdf'});

Все ровно ничего хорошего не получилось

Роман, данный функционал уже реализован в системе. Посмотрите в сервис FileService. К примеру для файла с страницы редактирования контактов достаточно сформировать тэг

<a target='_self' href='http://localhost:8087/0/rest/FileService/GetFile/e9eafee9-c4e4-4793-ad0a-003bd2c6a9b4/564a97fc-7290-4343-b45e-8f466e5fad5b"'></a>

Где e9eafee9-c4e4-4793-ad0a-003bd2c6a9b4 - UId объекта ContactFile, а 564a97fc-7290-4343-b45e-8f466e5fad5b - Id файла из таблицы ContactFile. UId будет проще всего скопировать напрямую с уже созданных линков на детали "Файлы и ссылки".

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

Задача:
Экспорт отчета FastReport в деталь Файлы в формате PDF для выделенных записей в реестре
Решение
1. В ShowSelectedRecordsReport добавляем SetAttribute(ReportPreviewer,'GridDatasetIDs',GridDatasetIDs);

function ShowSelectedRecordsReport(ReportCode, FilteredDatasetCode,
        GridDatasetIDs, FilterForm) {
        var Report = Services.GetNewItemByUSI(ReportCode);
        var ReportPreviewer = Services.GetNewItemByUSI('wnd_BaseFastReportPreview');
        var ReportPreviewerComponent = ReportPreviewer.Attributes('ReportPreviewer');
        var ReportDataset = Services.GetNewItemByUSI(FilteredDatasetCode);
        SetAttribute(ReportPreviewer, 'Report', Report);       
        var Select = GetSelectQueryPrimarySelect(ReportDataset.SelectQuery);
        var Filters = Select.Filters;
        Filter = GetSelectQueryFilterByCode(ReportDataset.SelectQuery, 'IDs');
        if (!Assigned(Filter)) {
            Filter = Filters.CreateIncludeFilter();
            Filter.Code = 'IDs';
            Filters.Add(Filter);
                Filter.TestExpression =
                        Filter.CreateFieldFilterExpression();
                Filter.TestExpression.TableAlias =
                        Select.FromTableAlias;
                Filter.TestExpression.Field =
                        Select.FromTable.Fields.ItemsByName('ID');
        }
        var Enabled = (GridDatasetIDs.length > 0);
        ApplyDatasetIncludeFilter(ReportDataset, 'IDs', GridDatasetIDs, Enabled);              
        if (Assigned(FilterForm)) {
                SetAttribute(ReportPreviewer, 'FilterForm', FilterForm);
                SetAttribute(ReportPreviewer, 'ShowFilterForm', true);
        }
       

        SetAttribute(ReportPreviewer,'GridDatasetIDs',GridDatasetIDs);

       
        ReportPreviewer.Build();
        ReportPreviewer.Prepare();  
        ReportPreviewerComponent.DatasetByUSI(FilteredDatasetCode) = ReportDataset;
}

2. В wnd_BaseFastReportPreviewScript дописываем

function  wnd_BaseFastReportPreviewOnClose(Window) {
         if (Window.ComponentsByName('frpMain').Report.Caption == 'Коммерческое предложение') {
          var GridDatasetIDs = GetAttribute(Window, 'GridDatasetIDs');
         var frpMain =  Window.ComponentsByName('frpMain');//ReportPreviewer.ComponentsByName('frpMain')           ;
                var TempFileName = System.CreateObject('TSObjectLibrary.Value');
                var FileNameStr = frpMain.Report.Caption;
                var Extension = '.pdf';
                TempFileName.Value = GetTemporaryFileName(FileNameStr + Extension, true);
                frpMain.Export(retPDF, TempFileName, false);
               
                for (var i=0 ; iGridDatasetIDs.length; i++)
                {
                  var ID = Connector.GenGUID();
                  var Dataset = Services.GetNewItemByUSI('ds_Files');
                  var DataFieldName = 'FileData';
                               //пишем файл в базу...
                               Dataset.Append();
                               Dataset.Values('ID') = ID;
                               //тип - файл
                               Dataset.Values('ItemTypeID') = '{39A5B367-4A7A-473E-8F74-26977CB6DB67}';
                               Dataset.Values('Link') = FileNameStr+ Extension;
                               Dataset.Values('Revision') = 1;
                               var FileSize = GetFileSize(TempFileName.Value);
                               if (FileSize > 0)
                               {
                                    Dataset.Values('FileSize') = FileSize;
                               }
                               SaveFileToDataset(TempFileName.Value, Dataset, DataFieldName);
                               Dataset.Post();
                               var FileID = ID;
                                               //получили Documents, теперь формируем полное имя сервиса insert query
//                                           IsertQueryLinkUSI = IsertQueryLinkUSI + 'Invoice'//Temp[1].substring(0, count);
                                               //и получаем экземпляр данного сервиса
                                               var InsertQuery = Services.GetNewItemByUSI('iq_FileInOffering');
                                               //заполняем параметры запроса        
                                               var ColumnsValues = InsertQuery.ColumnsValues;
                                               ColumnsValues.Items(1).Value = FileID;
                                               ColumnsValues.Items(2).Value = GridDatasetIDs[i];
                                               var IDs = Connector.GenGUID();
                                               ColumnsValues.Items(0).Value = IDs;
                                               //выполняем
                                               InsertQuery.Execute();
                             
                }
        }
       
        frpMain.Cancel();
}

Комментарий:
Мы делаем экспорт на событии закрытия пред просмотра отчета, так необходимо делать так как на OnShow, отчет еще не успевает сформироваться.
В данном примере в экспорт в деталь будет только для отчета с названием 'Коммерческое предложение' в деталь продукты (iq_FileInOffering) , если нужно выгружать все отчеты, уберите проверку.
Аналогичный код можно кинуть в ShowSelectedRecordsReport, в конце функции, но будет беда когда к отчету прикручено окно фильтрации, а отчет то не сформировался, и писать нечего, поэтому решено писать на событии закрытия предпросмотра.

Пожелание по улучшению:
1.Сделать универсальную подстановку InsertQuery, в духе того как это сделано тут Прикрепить отчет на деталь "Файлы" сразу после генерации Word отчета
2.Проверку делать не по Window.ComponentsByName('frpMain').Report.Caption а по USI

Нравится

Поделиться

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

Добрый день!

При экспорте отчета в PDF все символы языка, не установленного как 'language for non-unicode program', отображаются некорректно.
Экспорт в RFT проходит нормально.
Тестируем на 3.2.0.11, Windows Server 2003 "R2" Server

Спасибо!

Нравится

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

Terrasoft Support Team
Владимир, наиболее вероятной причиной возникновения подобной проблемы является особенность версии FastReport, с которой интегрирован программный продукт Terrasoft CRM для генерации отчетов. Данная проблема не воспроизводится на новой версии генератора отчета FastReport, интеграция с которой используется при разработке программного продукта Terrasoft CRM 3.3, официальный выход которого запланирован на ближайшее будущее. О выходе нового программного продукта с исправленной проблемой FastReport Вы сможете узнать на сайте Terrasoft.

Продолжая тему Unicode (а конкретно, русских букв на машине с другим языком по умолчанию), заметил еще 2 вещи (в той же 3.2.0.11):

1. При создании письма из шаблона, поле Subject в MS Outlook показывается знаками вопроса вместо русского названия
2. В Rich Text (например Контрагенты-Описание) невозможно ввести русский текст.

Это можно исправить настройками?

Спасибо!

Добрый день, Владимир!

К сожалению, поле Subject в теме создаваемого письма не является юникодным, и повлиять на это из TerrasoftCRM не удается, т.к. это элемент MS Outlook.
Насчет RichText - из конфигурации также повлиять не удастся, компонент реализован в ядре. В качестве варианта можно попробовать изменять шрифт.
Видимо, единственный путь - установить в "Пуск - Панель управления - Язык и региональные настройки" Русский язык.

Спасибо!

Попробую для себя прояснить ситуацию:
1. Ведь мы задаем кодировку в шаблоне сообщения. Допускаю, что можно перекодировать из Unicode (которые в TS) в формат, понятный для Subject MS Outlook. Ведь, написать вручную в Subject русскими буквами потом можно

2. Смена шрифтов не помогла. Но зато при копировании из Word'a, например, текст виден нормально. Насколько я знаю, RichText умеет отображать Unicode, но не умеет его воспринимать при вводе. Было бы здорово добавить какой-то другой контрол для ввода Unicode-описаний.

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

Для RichText помогло менять раскладку клавиатуры на нужную перед копированием текста в буфер

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