Добый день!
Опишу задачу для начала.
В карточке редактирования раздела есть вкладки конкретно "Ежегодная отчетность".
Собственно в ней два контейнера окон.
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);
	}

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

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

В этом блоге хочу рассказать о развитии Drag&Drop в версии 3.4.x+
Никому не секрет, что DataGrid «умеет» принимать файлы с помощью Drag&Drop. Такая функциональность реализована на детали «Файлы». Но, для того, чтобы файлы извлечь с детали «Файлы», к примеру, прикрепить к письму, требуется совершать операции по сохранению его на жесткий диск, а уж потом перемещать куда нужно. Данный способ манипулирования файлами занимает много времени. Поэтому, в DataGrid был добавлен функционал полноценного Drag&Drop. Теперь есть возможность сохранять файлы только с помощью мыши. Также, весьма немаловажным бонусом, появилась возможность копировать и вставлять файлы с помощью комбинаций Ctrl+C/Ctrl+V. Именно с помощью этих операций не обойтись при переносе файлов внутри системы (файлы из одной записи в другую, из одного раздела – в другой). Плюс к выше сказанному появилась «автогенерация файлов по формату». Т.е., при нажатии Ctrl+V система анализирует содержимое буфера и генерирует (+ сохраняет) файл нужного формата.
Поддерживаемые форматы:

  1. Все изображения. Любое изображение будет сохранено в PNG формате (даже если Вы нажали Print Screen, то система сгенерирует Вам готовый файл)
  2. RTF. Любой форматированный текст буде сохранен в формате *.rtf
  3. HTML. Любой текст с HTML разметкой будет сохранен в *.html файл
  4. TEXT. Любой текст, который не является RTF – будет сохранен в *.txt файл

Дальше речь пойдет о реализации этих возможностей. Для начала пройдемся по имеющимся, а также новым свойствам:
Pic 1

  • CanCopySystemObjects – свойство, которое разрешает или запрещает копирование с помощью Ctrl+C
  • CanDragDropSystemObjects – знакомое свойство с предыдущих версий, которое разрешает или запрещает Drag&Drop в систему. Однако, в 3.4.x оно еще отвечает и за Drag&Drop из системы
  • CanPasteSystemObjects – свойство, которое разрешает или запрещает вставку с помощью Ctrl-V

Также, помимо свойств, появились новые события:
Pic 2

  1. OnGetSystemObjectNames – в обработчике события нужно заполнить имена файлов, которые будут копироваться (файлы будут сохранены под этими именами и расширениями). По количеству имен в списке будут генерироваться события OnGetSystemObjectData
  2. OnGetSystemObjectData - это событие придет столько раз, сколько было задано имен файлов в обработчике события OnGetSystemObjectNames. И при каждом вызове будет прислан Index файла, данные которого нужны. В обработчике необходимо вернуть поток данных согласно индексу файла
  3. OnPasteSystemObject – данное событие будет генерироваться при нажатии Ctrl+V. В него будет передан список файлов, которые нужно сохранить
  4. OnGetSystemObjectText – данное событие генерируется в том случае, когда «приемник» файла не может принять файл, но может принять текст. Поэтому в обработчике можно изменить текст, который будет передан

Маленьким, но приятным бонусом, появилась возможность отображать иконки, зарегистрированные в Windows согласно расширению файла:
Pic 3
Для того, нужно в обработчике OnGetRowDrawInfo, параметру ImageName нужно установить значение имени файла с расширением. Причем имя значения не имеет, так как поиск будет происходить только по расширению файла. Пример:

function OnGetRowDrawInfo(DataGrid, Color, TextColor, ImageName, Font) {
ImageName.Value = 'File.docx'; //Все элементы будут отображать иконку Word’а
ImageName.Value = 'File.xls' //Все будут отображать иконку Excel
}

Перед тем, как подвести итог, я предоставлю код реализации этих возможностей:

//Эта функция идентична для сохранения файлов как на
//событие OnDragDropSystemObjects, так и на OnPasteSystemObjects
function InsertSystemObjects(SystemObjectsList) {
        var FilesArray = SystemObjectsList.CommaText.split(',');
        var FileNames = System.CreateObject('TSObjectLibrary.StringsList');
        for (var i = 0; i FilesArray.length; i++) {
                FileNames.Clear();
                var Path = FilesArray[i];
                while (Path.indexOf('"', 0) != -1) {
                        Path = Path.replace('"', '')
                }
                FileNames.Add(Path);
                if (!CheckFileExists(Path)) {
                        AddObject(ft_FolderLink, Path, 1, null);
                } else {
                        AddObject(ft_File, FileNames, 1, null);
                }      
        }
}
 
//Реакция на Drag&Drop
function grdDataOnDragDropSystemObjects(DataGrid, DataGridColumn, SystemObjectsList, DestinationRowID, DropMode, WithCtrl) {
        InsertSystemObjects(SystemObjectsList);
}

//Реакция на Ctrl+V
function grdDataOnPasteSystemObjects(DataGrid, DataGridColumn, SystemObjectsList, SelectedIDs) {
        InsertSystemObjects(SystemObjectsList);
}

//Запрос имен объектов, который нужно копировать
//Если, в обработчике , вы запретите копировать какой-то
//файл (не передадите его имя), то в обработчике события
//OnGetSystemObjectData вам также нужно реализовывать
//дополнительные проверки
function grdDataOnGetSystemObjectNames(DataGrid, SourceDataGrid, SelectedIDs, SystemObjectNames) {
        var Dataset = GetSingleItemByCode('ds_Files', 'SystemObjectsFileDetail');
        var FileDataDataField = Dataset.DataFields.ItemsByName('FileData');
        EnableDatasetFilters(Dataset, false, 'ID');
        EnableDatasetField(Dataset, FileDataDataField, false);  
        Dataset.Open();
        for (var i = 0; i SelectedIDs.Count; i++) {
                if (!Dataset.Locate('ID', SelectedIDs(i))) {
                        continue;
                }
                SystemObjectNames.Add(Dataset('Link'));
        }
        Dataset.Close();
}

//Как было сказано выше - это событие генерируется для
//каждого файла, имя которого было указано в обработчике
//события OnGetSystemObjectNames. Порядок в списке
//файлов совпадает с порядком генерации события.
//Т.е., параметр SystemObjectIndex – это индекс в списке имен файлов
function grdDataOnGetSystemObjectData(DataGrid, SourceDataGrid, SelectedIDs, SystemObjectIndex, SystemObjectData) {
        if (!SelectedIDs) {
                return;
        }
       
        if (SystemObjectIndex >= SelectedIDs.Count) {
                return;
        }
        var RecordID = SelectedIDs(SystemObjectIndex);
        var Dataset = GetSingleItemByCode('ds_Files', 'SystemObjectsFileDetail');
        var FileDataDataField = Dataset.DataFields.ItemsByName('FileData');
        ApplyDatasetFilter(Dataset, 'ID', RecordID, true);
        EnableDatasetField(Dataset, FileDataDataField, true);
        Dataset.Open();
        //Из Blob поля мы просто сохраняем значение в поток SystemObjectData
        Dataset.DataFields.ItemsByName('FileData').GetValAsBlob(SystemObjectData);
        Dataset.Close();
}

Важно для разработчика:

  1. События OnGetSystemObjectNames, OnGetSystemObjectData и OnGetSystemObjectText начинают приходить только после того, как вы нажали Ctrl+V или отпустили кнопку мыши (при перетаскивании файлов) вне зависимости от того наше ли это приложение, или же стороннее
  2. События OnGetSystemObjectNames, OnGetSystemObjectData и OnGetSyestemObjectText в качестве параметра SelectedIDs принимают список IDs записей, которые действительно были скопированы (это важно). Этот список может не совпадать с DataGrid.SelectedIDs или SourceDataGrid.SelectedIDs. Связано это с тем, что вы можете переносить файлы, к примеру, с одного договора – в другой, и при этом DataGrid == SourceDataGrid (ведь это та же деталь), а при переходе на другую запись основного реестра применится фильтр для детали, и SourceDataGrid .SelectedIDs уже будет содержать совершенно другие значения
  3. В событие OnGetSystemObjectNames в качестве параметра SystemObjectNames приходит уже созданный IStringsList, Вам не нужно его создавать или же уничтожать – нужно только заполнить
  4. В событие OnGetSystemObjectData в качестве параметра SystemObjectData приходит уже созданный IStream. Вам достаточно просто записать в него значение. Создавать или уничтожать его также не нужно
  5. Событие OnGetSystemObjectText приходит только тогда, когда «приемник» не может принять файл(ы) (к примеру, при вставке в открытый документ Word). В нем можно указать текст, который необходимо вставить
  6. Вы можете пропустить копирование какого-либо файла. Для этого достаточно внести изменения в код обработчика OnGetSystemObjectData:
  7. //Чтобы отменить копирование файла не обязательно его
    //отсутствие в списке файлов, достаточно отменить его по индексу
    function grdDataOnGetSystemObjectData(DataGrid, SourceDataGrid, SelectedIDs, SystemObjectIndex,   SystemObjectData) {
            if (!SelectedIDs) {
                    return;
            }
           
            if (SystemObjectIndex >= SelectedIDs.Count) {
                    return;
            }
           //К примеру мне не хочется, чтобы пользователь
           //скопировал 2-й выбранный файл
           //Для этого достаточно выйти из функции, не
           //заполняя поток SystemObjectData
           If (SystemObjectIndex == 1) {
              return;
    }
  8. Перемещение между DataGrid внутри системы осуществляется разными способами, в зависимости от установленных свойств. Рассмотрим 2 случая:
    1. Перемещение по умолчанию
    2. Pic 4

    3. Копирование файла(ов)
    4. Pic 5

      При манипуляции комбинациями Ctrl+C/Ctrl+V все аналогично, только учитывается свойство CanPasteSystemObjects

    Собственно, это все, что я хотел рассказать о развитии Drag&Drop’а.

    Приятной работы!

    P.S. Вся функциональность доступна в версиях 3.4.0.99+ и 3.4.1.16+

Нравится

Поделиться

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

Подскажите, есть ли возможность обновиться с версии 3.3.2.310 до версии 3.4? Необходимо получить возможность перетягивания файлов из Террасофт в письмо MS Outlook.
С какими проблемами можно столкнуться при этом (совместимость конфигурации 3.3.2 с версией бинарных файлов 3.4, прочее)?

Андрей, обновление возможно. Как один из вариантов - развернуть 3.4 и перенести данные из 3.3.2 на уровне БД. Также, необходимо согласовать изменение лицензий с ответственным менеджером со стороны Terrasoft.

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

Добрый день,

Помогите, пожалуйста, разобраться в ситуации.

Ситуация в следующем:

В компании с определенной периодичностью появляются файлы, относительно, большого размера (50-200 MB (макеты из граф. редакторов, аналитика, исслед. материалы и т.д.)). Эти материалы в основном не должны быть в общем доступе у всех пользователей, соответственно требуется распределять права.

Вот, тут появляется проблема, где их хранить:

- В БД mssql 2005. Не появятся ли, тогда проблемы со скоростью работы террасофта и сервера, когда объем базы вырастет до 10-ков GB? Из плюсов: решатся вопросы по доступам из террасофта и можно значительно уменьшить вероятность выноса этих данных.

- На сервере. Из плюсов: хранение файлов упирается только в жесткие диски. Из минусов: организация доступов пользователям из террасофта и труднее уменьшить вероятность выноса этих данных.

Буду очень благодарен за советы.

Нравится

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

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

В MS SQL 2008 R2 есть возможность хранить файлы отдельно от базы. Для Terrasoft и для конечных пользователей ничего не изменится.
http://community.terrasoft.ua/forum/topic/5410

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

Друзья, кто из вас организовывал хранение файлов при помощи FileStream?
Если да, то не могли бы вы поделиться опытом?
Рассказать в чем плюсы и минусы?
И как можно перейти от хранения файлов в таблице tbl_Files к хранению файлов в файловой системе при помощи file stream?

Нравится

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

Вот есть хорошая статья по организации FileStream
http://blogs.msdn.com/b/alexejs/archive/2009/06/03/filestream.aspx
Основное достоинство этой технологии - это то что объем хранимой информации не влияет на общий объем БД, а следовательно можно пользоваться MS SQL Server 2008 R2 Express Edition бесплатно еще какое-то время, пока база не станет объемом 4 Gb.

Туда бы еще и содержимое tbl_MailMessage отправить:smile:

Основной размер писем составляют аттачи. В новой версии почтового клиента аттачи вынесены в tbl_Files. Именно с этой целью. :wink:

"Евгений Либин" написал:В новой версии почтового клиента

кстати сразу еще один дополнительный + к выбору именно вашей версии выходит при условии реализации внешнего хранения файлов - убираем из бюджета Outlook и полновесный SQL server:smile:

Кстати, в инете не раз находил информацию о том что в MS SQL 2008R2 Expr. ed. размер базы увеличен с 4Гб до 10Гб, но на сайте микрософта подтверждения не нашел. Если это правда - то тогда это супер.

Строго говоря и 4Гб без хранения файлов и подобного более чем достаточно было бы... правда, там еще ограничения конечно есть в плане процессоров, памяти и т.д, да и про tbl_SystemLog со скриншотами не забываем:) в рамках оффтопика...

"Евгений Либин" написал:Вот есть хорошая статья по организации FileStream
http://blogs.msdn.com/b/alexejs/archive/2009/06/03/filestream.aspx
Основное достоинство этой технологии - это то что объем хранимой информации не влияет на общий объем БД, а следовательно можно пользоваться MS SQL Server 2008 R2 Express Edition бесплатно еще какое-то время, пока база не станет объемом 4 Gb.

спасибо, Евгений :) очень познавательно.

кстати, а как быть с backup? как происходит бэкап данных при использовании filestream?

Hello, colleagues !
This link really helped, thank You :). Have You tested the solution with table tbl_Files? I noticed, that some "instead of" triggers have to be removed to be able to change column FileDate datatype from Image to Varbinary, that use FileStreams. This cause access rights functionality.

Это решение уже кто-то в реальном проекте использовал? Или всё на стадии интереса?

"Евгений Либин" написал:Основной размер писем составляют аттачи. В новой версии почтового клиента аттачи вынесены в tbl_Files. Именно с этой целью.

У нас например за два года работы эта таблица выросла уже до 36гб (лимит Firebird), есть ли наработки по разделению таблицы tbl_Files на несколько? Например с UNION в SELECT запросе и подмене в INSERT`е и насколько это повлияет на производительность?

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

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

Спасибо Дмитрий, значит будем тестировать...

Добрый день!
Возвращаясь к filestream, можно его все-таки использовать в Террасофте для таблицы файлов или нет?
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) Зашла в террасофт, добавили файл, файл даже добавился файловую группу, но террасофт его не может потом прочесть, потому что видимо не подозревает про тип варбинари с признаком файлстрим

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

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

Товарищи, есть такая проблема.
Когда нажимаешь на кнопку копировать в реестре записей, то открывается карточка, ты меняешь название и другие поля, и ты по сути делаешь новую версию старой карточки.
Можно ли делать такое с файлами? Т.е ты по сути копируешь файл, меняешь его название и делаешь новую версию, оставляя старую (Файл1 -> Копировать -> Открывается Карточка файла -> Изменение -> Сохранение -> На детали файлы остаются Файл1 и Файл1.2)

Нравится

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

Можно сделать, например, так:

1) Создать новый ActionMenuItem в окне wnd_FilesDetailGridArea (например, с названием amiCopy). Создать для него обработчик события OnExecute.

2) Думаю, смысл копирования есть только для объектов с типом "Файл". Все остальные (ссылки, URL и т.д.) будут ссылаться на одно и то же место, поэтому нет смысла в их дублировании. Следовательно, в обработчик amiCopyOnExecute добавляем такой код:

function amiCopyOnExecute(ActionMenuItem, Sender) {
	var ItemTypeID = dlData.Dataset.Values('ItemTypeID');
	if (ItemTypeID == ft_File) {
		CopyFilesDetailRecord();
	}
}

3) Осталось создать функцию CopyFilesDetailRecord:

function CopyFilesDetailRecord() {
	var Dataset = dlData.Dataset;
	var FileID = Dataset.Values('ID');
	var NewFileID = ProcessCopyFile(FileID);
	RefreshDataset(Dataset);
	Dataset.Locate('ID', NewFileID);
	ProcessEditFileProperties();
}

Спасибо, Олег!
Очень выручили :)

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

Появился вопрос:
Когда я удаляю созданный документ в разделе Документы, то файлы прикрепленные к нему на детали Файлы (файлы сохранены в базу данных) остаются в базе данных. Т.е. чтобы не оставлять этот мусор в базе мне приходиться перед удалением документа вручную удалить прикрепленные файлы.
Как сделать чтобы при удалении документа связанные с ним файлы (сохраненные в базу данных) удалялись автоматически ?
---------------
TS CRM 3.3.1.72
MSSQL 2005

Нравится

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

Наверное придется в обработчик клика кнопки "удалить" писать код для удаления файлов.
Или на вкладке деталей сначала поудалять файлы а потом удалить документ.
Можно еще каскадное удаление сделать для таблицы документ

Только что проверил на 3.3.1 SoftKey - действительно, есть такая проблема. Если удалить "Документ", то триггер (для каскадного удаления) удаляет только линк из таблицы tbl_FileInDocument, а вот сам файл остается в таблице tbl_Files (мусор). Но, если удалить файл из детали "Файлы", тогда он удаляет за собой (опять триггер) из tbl_Files.
Вот здесь бы и пригодилась идея Алексея: http://community.terrasoft.ua/ideas/2789 очень жаль, что отложили :cry:

--
www.it-sfera.com.ua

И все же вернемся к вопросу: каков на данный момент наиболее быстрый и простой способ решения данной ситуации ?

К датасету ds_Document надо добавить обработчик события OnAfterDelete, в котором удалять те файлы из tbl_Files, на которые есть ссылки в tbl_FileInDocument, то есть:
- tbl_FileInDocument.DocumentID = ID удаленного документа
- tbl_FileInDocument.FileID = ссылки на tbl_Files

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

--------------------------------------------
Лабитек
Центр разработки приложений

Спасибо будем посмотреть.

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

Было бы хорошо реализовать drag'n'drop файлов из TS в Windows и наоборот. Думаю, что это не сложная техника.
И тоже самое с Outlook - перетащить несколько файлов из разных разделов в attachment и сохранить файлы из attachment'а в нужные разделы (как привязка e-mail к какой-либо сущности).

Нравится

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

Добрый день.

Спасибо за Ваш вопрос.

Возможность перемещать файлы из рабочей области Windows на закладку Менеджера Деталей Файлы есть, но операций с этими файлами никаких не выполняется. Вы можете самостоятельно сконфигурировать обработчик события, которое происходит при перемещении файла на закладку Файлы.

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

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

Будем рады ответить на все Ваши дополнительные вопросы.

Terrasoft Support Team

"support" написал:В приложении аналогичная функциональность ранее реализована не была.

А начиная с какой версии в системе появился этот функционал?
У нас используется 3.1.1.6. Я так понимаю, нам этот счастье не светит?

Добрый вечер, Алексей!

Данная возможность появилась в версиях 3.2.0.х. Если указанная функциональность очень критична, стоит рассмотреть вариант перехода на версию 3.2.0 (а лучше заодно на 3.2.1).
На версии 3.1.1.х данную функцию средствами конфигурации реализовать не удастся, т.к. основной код реализован в ядре системы.

Всегда рад ответить на Ваши вопросы.

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

Здравствуйте!
Создала в новом разделе в деталях вкладку Файлы1, Файлы2. При удалении файлов из деталей раздела они исчезают с грида, но в базе остаются. Это можно просмотреть с помощью SQL Navigator'a. Проверяла со вкладками Файлы стандартных разделов. Файлы из базы удаляются тоже. Скажите, пожалуйста, почему в моем случае файлы удаляются только из грида, а в базе остаются?

Нравится

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

Добрый день, Екатерина.
Нужно анализировать содержимое таблиц tbl_FileInMyRazdel и tbl_Files.
В Вашем случае, видимо, были успешно удалены записи из tbl_Files, но не удалены записи из tbl_FileInMyRazdel. Для исправления ошибки необходимо в таблице tbl_FileInMyRazdel для обоих внешних ключей установить признак "Каскадный", что означает каскадное удаление записи в tbl_FileInMyRazdel при удалении записи в tbl_Files, которое происходит при нажатии на кнопку "Удалить" в реестре детали.
Желаю успехов!

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

Доброго дня! Нужно проверить есть ли действительно эти ключи в структуре базы. Возможно, что имело место сохранение сервиса без обновления структуры. Если ключей нет, то необходимо пересохранить сервис таблицы.
Возможно так же, что была использована не стандартная деталь, а некоторая, созданная своими силами, тогда необходимо описание что и как было сделано.
Так же, возможно, что в качестве набора данных для детали был указан набор данных ds_FileInMyRazdel вместо стандартного ds_FileInItem и тогда записи удаляются только из таблицы связки, а сами файлы остаются. В этом случае надо привести деталь к стандартному виду.

Спасибо! Действительно в Администраторе внешние ключи были, а в самой базе их не было.

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