Добрый день!

Считаю, что была бы полезной функция наглядного наличия вложенного файла в Обращении,

например, такого вида:

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

Если реализовывать самостоятельно такую логику, проще всего будет доработать присвоение номера при создании обращения или добавить его изменение. Скрепку можно выводить как символ: ?.Только учесть, чтобы не сломалась привязка писем по номеру обращения в них.

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

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

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

Желательно присутствие бывалых Одинов, которые повидали многое в данном продукте.
В продолжение предыдущего поста было принято решения не отходить от стандартной реализации отправления файла, используя 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'ить эти части между собой. Но мысли пока зашли в тупик.

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

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

Добрый день!
Возвращаясь к filestream (топик http://www.community.terrasoft.ru/forum/topic/5410), можно его все-таки использовать в Террасофте для таблицы файлов или нет?
TS 3.4.1.
SQL 2014
Террасофт умеет работать с данными типа varbinary(max) filestream?

1) включили возможность файстрима на сервере
2)создали файловую группу для базы
3)в качестве проверки функциональности создали новую таблицу через sql, там поле varbinary(max) filestream-засунули туда данные через sql - ну тут все ок
4) добавили в таблицу tbl_Files новое поле FileData1 varbinary(max) filestream; (перед этим пришлось удалить триггер к этой таблице - на instead of delete)
5) Пошли в террасофт администратор, там взяли в таблице tbl_Files, полe FileData сменила на FileData1 (не меняя при этом тип, и не сохраняя в бд потом таблицу (потому как не видим типа varbinary в приложении), пошли в sq_Files - там выбрали FileData1 вместо FileData.
6) Зашли в террасофт, добавили файл, файл даже добавился файловую группу, но террасофт его не может потом прочесть, потому что видимо не подозревает про тип варбинари с признаком файлстрим

Есть пути решения?

Нравится

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

Работа с filestream обсуждалась тут и тут. Также тут обсуждают альтернативные реализации с хранением в другой базе.

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

Добрый день!

Как в TS 3.X лучше работать с zip-архивами (распаковать файлы, упаковать файлы)?

Нравится

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

Думаю, стоит использовать какой-то COM-объеккт и вызывать его методы. Например, стандартный в Windows объект Shell.Application тоже умеет работать с ZIP.

Добрый день.
Все зависит от поставленной задачи.

Самый простой способ, это использовать встроенный Zip-архиватор ОС Windows.

Пример использования:

function Main() {
    var zFolder = "c:\\log.zip";
    var eFolder = "c:\\log";
 
    ExtractFileFromZip(zFolder, eFolder);
    CompriseFileToZip(eFolder, zFolder);
}
 
function ExtractFileFromZip(PathFrom, PathTo) {
    var FSO = new ActiveXObject("Scripting.FileSystemObject");
    var App = new ActiveXObject("Shell.Application");
    if (FSO.FolderExists(PathTo)) {
    	FSO.DeleteFolder(PathTo, true);
    }
    FSO.CreateFolder(PathTo);
    var FolderPathTo = FSO.GetFolder(PathTo).Path;
    var FolderPathFrom = App.Namespace(FSO.GetFile(PathFrom).Path);
    var ZipItems = App.Namespace(FolderPathFrom).Items();
    App.Namespace(FolderPathTo).CopyHere(ZipItems);
}
 
function CompriseFileToZip(PathFrom, PathTo) {
    var Str = "PK%05%06%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00";
    var ForWriting = 2;
    var FSO = new ActiveXObject("Scripting.FileSystemObject");
    var App = new ActiveXObject("Shell.Application");
    if (FSO.FileExists(PathTo)) {
    	FSO.DeleteFile(PathTo, true);
    }
 
    var Itm = FSO.OpenTextFile(PathTo, ForWriting, true);
    Itm.Write(unescape(Str));
    Itm.Close();
 
    var Enm = new Enumerator(FSO.GetFolder(PathFrom).Files);
    for (; !Enm.atEnd(); Enm.moveNext()) {
    	Itm = Enm.item();
    	App.Namespace(FSO.GetFile(PathTo).Path).CopyHere(Itm.Path);
	}
}
Показать все комментарии

Добрый день!
Как можно выгрузить все файлы из детали файлы и ссылки в сетевую папку на диск?
Сделать это нужно программно.

Нравится

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

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

bpmonline не предполагает таких операций. Тем не менее данную задачу можно попробовать реализовать через бизнес процесс. Вам необходимо перебрать все записи в соответствующей таблице (объекте). Для каждого раздела объект "Файлы и ссылки" свой (как и таблица в базе данных).

1) Начальный элемент
2) Получение данных о файле элементом "Чтение данных"
3) "Исключающее ИЛИ" с двумя условными потоками (если файлов для выгрузки больше нет, то конец процесса), иначе идем дальше.
4) Элемент "Задание-сценарий" с приблизительным кодом:

   public static string SaveDecompressFile(string FileName, SqlBytes CompressedFile)
    {
        if (CompressedFile.IsNull)
        return "Error";
 
        DeflateStream decompress = new DeflateStream(CompressedFile.Stream, CompressionMode.Decompress, true);
 
        try
        {
 
            FileStream file = File.Create(FileName);
 
            int sourcebyte = decompress.ReadByte();
            while (sourcebyte != -1)
            {
                file.WriteByte((byte)sourcebyte);
                sourcebyte = decompress.ReadByte();
            }
 
            file.Close();
        }
 
        catch (Exception)
        {
            return "Error";
        }
 
        finally
        {
            decompress.Close();
            decompress = null;
        }    
 
        return "OK";
    }

(источник)

Далее возвращаемся на элемент "Чтение данных".

В таком бизнес процессе необходимо будет увеличить максимальное число повторений (настраивается в свойствах процесса).

Все оказалось даже проще.
Может кому-то пригодится
Для работоспособности в using нужно добавить System.IO

//получаем stream из Entity 
MemoryStream ms=documentFile.GetStreamValue("Data");
//записываем его в файл
ms.SaveToFile(dir+name);  

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

 [OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped,
    RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
public void fileUnloadling(
	string documentId, //Id докумена
	string documentNumber
	)
{
	if (System.Diagnostics.Debugger.IsAttached)
	{
	    System.Diagnostics.Debugger.Break();
	}
	var UserConnection = (UserConnection)HttpContext.Current.Session["UserConnection"];
	var dir=Terrasoft.Core.Configuration.SysSettings.GetValue(UserConnection, "SxFilePathForUnloading")+documentNumber+"\\";
	EntitySchema schema = UserConnection.EntitySchemaManager.GetInstanceByName("DocumentFile");
    EntitySchemaQuery esq = new EntitySchemaQuery(schema);
    esq.AddAllSchemaColumns();
    esq.Filters.Add(esq.CreateFilterWithParameters(FilterComparisonType.Equal, "Document", documentId));
    esq.Filters.Add(esq.CreateFilterWithParameters(FilterComparisonType.Equal, "Type", "529BC2F8-0EE0-DF11-971B-001D60E938C6")); //тип файл
 
    EntityCollection documentFileEntities = esq.GetEntityCollection(UserConnection);
    foreach (Entity documentFile in documentFileEntities  )
    {
        var name=documentFile.GetTypedColumnValue<string>("Name");
		MemoryStream ms=documentFile.GetStreamValue("Data");
        try
		{
			if (!Directory.Exists(dir))
                    {
                        Directory.CreateDirectory(dir);
                    }
			ms.SaveToFile(dir+name);  
		}
		catch (Exception e) 
		{
 
		}
    }
 
}    }

Пащенко Александр Сергеевич

а как мы определяем из детали какого объекта файлы и ссылки и какой именно записи это объекта забираем файлы?

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

В моем случае не нужно было универсальное решение для всех объектов. Как вариант, можете в параметрах прокидывать название объекта или родительской схемы и идентификатор записи. 

Какая у Вас задача?

Пащенко Александр Сергеевич,

После завершения активности хотелось бы выгружать все приложенные файлы на детали Файлы и ссылки в отдельную папку в хранилище.

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

Тогда можете в БП отловить сигналом завершение активности, а дальше скриптом выгружать из ActivityFile.

Учтите, что в детали еще могут быть ссылки. Нужно в запрос добавить фильтр по типу

Схемы файлов обычно называются по шаблону [название раздела] + "File"

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

bpm 7.2 on-site

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

Нравится

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

Здравствуйте, Илья.

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

Google Chrome:

http://i62.fastpic.ru/big/2014/0523/33/6e4b9e46c9a40fe7d09b623db5e6dc33.png

Mozilla Firefox:

http://i62.fastpic.ru/big/2014/0523/33/0ce94959f221827fa4b780f59028e133.png

"Соколов Илья Андреевич" написал:файлы не скачивались, а сразу предлагалось открытие системой

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

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

Имеется деталь "контакты" и у каждого контакта есть, привязанные к нему файлы. Мне необходимо на другой детали получить список привязанных файлов. В дереве нашел dataset ds_Files (при выводе этих данных на экран все работает - выводятся все файлы для всех контактов). Дело остается за малым - отфильтровать по ContactID, однако данное поля в датасете ds_Files нет. Я не могу найти это самое связующее поле. Кто-нибудь знает?

Нравится

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

Если вдруг кому-нибудь пригодится:

Все файлы хранятся в таблице tbl_Files, информация о принадлежности файла к записям разделов хранится в таблицах развязки (например, tbl_FileInAccount, tbl_FileInContact).

Соответственно, для получения названия файла (колонка Link таблицы tbl_File), Вам необходимо получить идентификатор записи файла из таблицы развязки, отфильтровав записи по идентификатору записи раздела. Затем, получить информацию из таблицы файлов по идентификатору.

Здравствуйте, Александр Сергеевич!

У Вас остались еще вопросы касательно данной темы?

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

Добый день!
Опишу задачу для начала.
В карточке редактирования раздела есть вкладки конкретно "Ежегодная отчетность".
Собственно в ней два контейнера окон.
1. Это Ежегодная отчетность .
2. Это файлы что крепятся к созданным отчетам.
В принципе все работает добавляю запись в первую таблицу к ней могу крепить файлы но! Когда прицепляю файл у меня выскакивает ошибка (см. скриншот) но файлы цепляются
код инстализации вкладки "Ежегодная отчетность"

function InitializeReportingFromPartsnWindow(Window) {
        var  Wnd = wndReportingFromPartsDetail.Window;
        var Dataset = dlData.Dataset;
        var RecordID = Dataset.Values('ID');
        Wnd.Attributes('DatasetUSI') = 'ds_ReportingFromParts';
        Wnd.Attributes('ParentItemFieldName') ='PartsID';
        Wnd.Attributes('ParentItemID') = RecordID;
        Wnd.Prepare();

        var WndDataset = Wnd.ComponentsByName('dlData').Dataset;
        RefreshDetailData(Dataset, 'ID', WndDataset, 'PartsID');


        var WndFiles = wndFilesDetail.Window;
        WndFiles.Attributes('DatasetUSI') = 'ds_FileInItem';
        WndFiles.Attributes('TableUSI') = 'tbl_FileInRepotingFromParts';
        WndFiles.Attributes('InsertLinkUSI') = 'iq_FileInRepotingFromParts';
        WndFiles.Attributes('ParentItemFieldName') = 'ReportingID';
        WndFiles.Attributes('ParentItemID') = WndDataset.ValAsStr('ID');
        WndFiles.Attributes('NotifyObject') = wndReportingFromPartsDetail.Window;
        WndFiles.Attributes('ItemRightsTable') = WndDataset.SelectQuery.Items(0).FromTable.RightsTable;    
        WndFiles.Prepare();
        var WndDatasetFile = WndFiles.ComponentsByName('dlData').Dataset;

        RefreshDetailData(WndDataset, 'ID', WndDatasetFile, 'ItemID');
                if((Dataset.State==3)||((Dataset.State!=3)&&(Dataset.State!=2))){
                Wnd.ComponentsByName('btnAdd').IsEnabled = false;

        }
       
}

Нравится

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

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

Не могу посмотреть вложение - "нет прав". Можете вставить вложение прямо в пост, или опубликовать где либо на стороннем хостинге?
Лучше всего, конечно, активировать отладчик, и найти строку с ошибкой в Visual Studio.

Скорее всего она в этой строке

WndDataset.SelectQuery.Items(0).FromTable.RightsTable;

[url=http://postimg.org/image/4kphtna3f/][img]http://s17.postimg.org/4kphtna…]
Отладчик не выходит в этот момент.
WndDataset.SelectQuery.Items(0).FromTable.RightsTable; - если дело в этом то даже если эту строку убрать ошибка будет та же. У таблици отчетов нету RightsTable

Рустам, а если закомментировать всё тело функции, ошибка останется (может она и вовсе не в ней)?

Попробуйте после каждой строки написать код:

Log.Write(1, 'строка 0');
..
Log.Write(1, 'строка 1');
..
Log.Write(1, 'строка 2');

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

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

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

Вы были правы ошибка именно в
WndDataset.SelectQuery.Items(0).FromTable.RightsTable; - потому что это null
Возможно ли без этого параметра ?

Спасибо за помощь решил проблему подставил родительский dataset )

Рустам, всегда пожалуйста.

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

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

Нравится

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

и возможно ли это?

Подобный вопрос рассматривался здесь http://www.community.terrasoft.ua/blogs/2952

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

Добрый день!

Предлагаю ко вниманию реализацию автоматического добавления сгенерированного Word отчета для записи раздела на деталь "Файлы".
Для этого необходимо внести следующие изменения в функцию function ShowWordReport(UserReportData, WorkspaceRecordIDs, WorkspaceWindow) скрипта scr_UserReportCommon:

Document.Save();

var ID = Connector.GenGUID();
var FileName = BuildFilePath(Document.Path, Document.Name);
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') = Document.Name;
Dataset.Values('Revision') = 1;
var FileSize = GetFileSize(FileName);
if (FileSize > 0)
{
     Dataset.Values('FileSize') = FileSize;
}                                              
SaveFileToDataset(FileName, Dataset, DataFieldName);
Dataset.Post();                                
var FileID = ID;
var IsertQueryLinkUSI = 'iq_FileIn';
var Temp = WorkspaceWindow.USI.split('_');             
var count = 0;
for(var i = 0; i Temp[1].length; i++)
{
        if(Temp[1].charAt(i) == 'W' && Temp[1].charAt(i+1) == 'o')
        {
                count = i - 1;
                break;
        }
}  
IsertQueryLinkUSI = IsertQueryLinkUSI + Temp[1].substring(0, count);
var InsertQuery = Services.GetNewItemByUSI(IsertQueryLinkUSI);        
var ColumnsValues = InsertQuery.ColumnsValues;
ColumnsValues.Items(1).Value = FileID;
ColumnsValues.Items(2).Value = WorkspaceRecordIDs[0];
var IDs = Connector.GenGUID();
ColumnsValues.Items(0).Value = IDs;
InsertQuery.Execute();

Добавить приведенный выше код необходимо перед строкой

return Document;

в конце функции.

Приятной работы с Terrasoft.

Нравится

Поделиться

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

Здравствуйте!
Пытался использовать ваш код в конфигурации. Но возникла проблема, решение которой я так и не нашел. Суть проблемы здесь.

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

Добрый день!
Я так понимаю, что решение было предоставлено тут

Добрый день.Поставил ваш скрип и вроде все нормально работает,но у меня задание немного другое и что бы его сделать нужно немного переделать код,а для этого нужно в нем детально разобраться.Не понятно к чему относится и откуда берется iq_FileIn,где задается Temp[1].length и зачем нам цикл:
for(var i = 0; i < Temp[1].length; i++)
{
if(Temp[1].charAt(i) == 'W' && Temp[1].charAt(i+1) == 'o')
{
count = i - 1;
break;
}
}

Дмитрий не могли бы вы написать не большие коменты в коду?Я просто только начинаю писать на JScripte и некоторые моменты не понятны-на С++ немного не так все))

Здравствуйте, Егор!

Код с комментариями ниже. Если будут дополнительные вопросы - обращайтесь.

//необходимо сохранить документ, чтобы на деталь сохранялся не шаблон, а заполненный отчет.
Document.Save();
 
var ID = Connector.GenGUID();
//получаем ссылку на файл
var FileName = BuildFilePath(Document.Path, Document.Name);
//получаем ссылку на датасет, куда будем записывать файл
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') = Document.Name;
Dataset.Values('Revision') = 1;
var FileSize = GetFileSize(FileName);
if (FileSize > 0)
{
     Dataset.Values('FileSize') = FileSize;
}                                           
SaveFileToDataset(FileName, Dataset, DataFieldName);
Dataset.Post();
//далее нужно привязать этот файл к той сущности для которой был вызван отчет и поместить его на деталь "файлы"                                
var FileID = ID;
//в базовой конфигурации есть готовые insert query запросы. Они имеют вид iq_FileIn[WorkspaceName]. Нам нужно узнать с какого раздела мы запустили данный отчет, и получить ссылку на этот сервис insert query. Заполнить необходимые параметры для него, и выполнить.
//получаем первую часть имени сервиса (константа)
var IsertQueryLinkUSI = 'iq_FileIn';
//получаем USI раздела. к примеру wnd_DocumentsWorkspace. режем его по "_", и далее обрезаем, чтобы получить только Documents
var Temp = WorkspaceWindow.USI.split('_');              
var count = 0;
for(var i = 0; i < Temp[1].length; i++)
{
        if(Temp[1].charAt(i) == 'W' && Temp[1].charAt(i+1) == 'o')
        {
                count = i - 1;
                break;
        }
}   
//получили Documents, теперь формируем полное имя сервиса insert query
IsertQueryLinkUSI = IsertQueryLinkUSI + Temp[1].substring(0, count);
//и получаем экземпляр данного сервиса
var InsertQuery = Services.GetNewItemByUSI(IsertQueryLinkUSI);
//заполняем параметры запроса        
var ColumnsValues = InsertQuery.ColumnsValues;
ColumnsValues.Items(1).Value = FileID;
ColumnsValues.Items(2).Value = WorkspaceRecordIDs[0];
var IDs = Connector.GenGUID();
ColumnsValues.Items(0).Value = IDs;
//выполняем
InsertQuery.Execute();

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

var Dataset = dlData.Dataset;
Dataset.Open();
var Resume = Dataset('Resume');
var ContactName = Dataset('Name');
var ID = Dataset('ID');
var ContactTypeID = Dataset('ContactTypeID');
if (ContactTypeID == '{3D51B409-B691-4F77-9723-359C65399AB4}') {
var Word = new ActiveXObject('Word.Application');
Word.Visible = false;
Word.Documents.Add();
Word.ActiveDocument.SaveAs(ContactName);
Word.ActiveDocument.Content.Text = Resume;
Word.ActiveDocument.Close();
}

Здравствуйте, Егор Андреевич.

Да, Вам и переделывать ничего не нужно. Просто скопируйте приведенный на 2 поста выше код в функцию function ShowWordReport(UserReportData, WorkspaceRecordIDs, WorkspaceWindow) скрипта scr_UserReportCommon. Единственный момент, нужно чтобы был создан отчет в разделе "Отчеты" меню "Инструменты", и данный отчет отображался в меню "Отчеты" раздела "Опросы".

Если же у Вас отчета нету, а строите Вы его динамически из кода, то в зависимости от того в каком из скриптов Вы стоите Word документ, нужно подключить туда скрипт scr_FileUtils, а также вместо объекта Document использовать имя Вашего word-объекта (Word).

Кстати, есть такое дополнение.
Мы его с Дмитрием как раз и делали.
Чтобы файл не только сохранялся на деталь, но и обновлялся при изменении, так, как будто вы его открыли с детали файлов - с запросом "Сохранить измененный файл в базу данных? Да\Нет", но только сразу после формирования отчета - без необходимости закрывания\открывания :wink:

"Олейник Дмитрий" написал:
необходимо в функцию, где у Вас автоматически сохраняется запись на деталь файлы, подписаться на этот файл:

var InsertQuery = Services.GetNewItemByUSI(IsertQueryLinkUSI);
//заполняем параметры запроса        
var ColumnsValues = InsertQuery.ColumnsValues;
ColumnsValues.Items(1).Value = FileID;
ColumnsValues.Items(2).Value = '{EF3C7392-8A38-459E-AB36-94565FD62464}';
var IDs = Connector.GenGUID();
ColumnsValues.Items(0).Value = IDs;
//выполняем
InsertQuery.Execute(); 
var Self = Services.GetNewItemByUSI('wnd_FilesDetailGridArea');
var fnFiles = Self.ComponentsByName('fnFiles');
fnFiles.UnsubscribeFileEvents(FileID);
fnFiles.SubscribeFileEvents(FileName, FileID);
return Document;

Но, т.к. подписались мы не из детали «Файлы», необходимо модифицировать функцию SetFileIsChanged скрипта scr_FilesDetailGriaArea:

function SetFileIsChanged(FileChangeNotifier, FileName, FileID) { 
         var Dataset = FilesDetailGridArea.ChangedFilesDataset;
         if (Dataset == undefined)
            {
                        var Dataset = Services.GetNewItemByUSI('mds_DictionaryTemplate');
                        if (IsCanSaveChangeFile(FileID)) {                   
                        Dataset.Append();
                        Dataset.ValAsGUID('ID') = FileID;
                        Dataset.ValAsStr('Name') = FileName;
                        Dataset.Post();                   
                        if (ShowConfirmationDialog(DoYouWantToSaveChangedFileToDatabase) ==
                                   mrYes) {
                                   SaveFileInDataBase(FileID, FileName);
                                   dlData.Dataset.RefreshRecord(FileID, false);
                                   Dataset.Delete();                           
                        }
                        return;                       
            }
         }
         if (IsCanSaveChangeFile(FileID)) {
                   Dataset.DisableEvents();
                   Dataset.Append();
                   Dataset.ValAsGUID('ID') = FileID;
                   Dataset.ValAsStr('Name') = FileName;
                   Dataset.Post();
                   RefreshGrid();
                   if (ShowConfirmationDialog(DoYouWantToSaveChangedFileToDatabase) ==
                            mrYes) {
                            SaveFileInDataBase(FileID, FileName);
                            dlData.Dataset.RefreshRecord(FileID, false);
                            Dataset.Delete();
                            RefreshGrid();
                   }
                   Dataset.EnableEvents();
         }
}

ПС. Я пробовал

var Self = Services.GetNewItemByUSI('wnd_FilesDetailGridArea');
var fnFiles = Self.ComponentsByName('fnFiles');
fnFiles.UnsubscribeFileEvents(FileID);
fnFiles.SubscribeFileEvents(FileName, FileID);

вынести в отдельную функцию - не прокатывает, терра зависает (видимо связано с особенностями установки триггеров для функций)

кстати, раздел Продаж называется wnd_OpportunitiesWorkspace, а не wnd_OpportunityWorkspace из-за чего данный код там не срабатывает
надо

var Temp = WorkspaceWindow.USI.split('_');              
var count = 0;
for(var i = 0; i < Temp[1].length; i++)
{
        if(Temp[1].charAt(i) == 'W' && Temp[1].charAt(i+1) == 'o')
        {
                count = i - 1;
                break;
        }
}  
IsertQueryLinkUSI = IsertQueryLinkUSI + Temp[1].substring(0, count);

заменить на

var Temp = WorkspaceWindow.USI.split('_');              
	var count = 0;
	if (Temp[1] == 'OpportunitiesWorkspace') {
		InsertQueryLinkUSI = 'iq_FileInOpportunity';
	} else {
		for(var i = 0; i < Temp[1].length; i++)	{
		        if(Temp[1].charAt(i) == 'W' && Temp[1].charAt(i+1) == 'o')
		        {
		                count = i - 1;
						break;
				}
		}   
		InsertQueryLinkUSI = InsertQueryLinkUSI + Temp[1].substring(0, count);
	}

Да, Вы правы, спасибо за исправление.

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