Коллеги, здравствуйте!
Написан БП по передаче обращений в продажи(т.е. создается лид). Если в обращении прикреплен файл, соответственно этот файл добавляем на деталь файлы, и его тоже нужно будет передать на деталь Файлы и Примечания в лидах.С помощью обычных блоков в БП этого сделать не удалось - БП завершался с ошибкой. Как тогда можно поступить в данном случае? Может, кто уже реализовывал данный кейс?

Нравится

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

Реализовать это можно. Не совсем, конечно понятна фраза "этот файл добавляем на деталь файлы, и его тоже нужно будет передать на деталь Файлы и Примечания в лидах".

1. Вам необходимо знать Id обращения, файлы которого вам нужно скопировать в Лид.
2. Не рекомендую реализовывать такие действия в том же БП где вы пытаетесь создать Лид, так как Лид до конца не создается (скорее всего), но как только закончит действие БП по созданию Лида, можно сделать второй БП который будет стартовать по сигналу Создания записи в таблице Лид (так же можно будет их отсеять от обычных Лидов любым вашим уникальным значением).
3. В этом втором БП который будет ловить сигнал создания Лида, вам необходимо добавить буквально один элемент "Добавить данные". В поле "В какой объект добавить данные" указать "Файл и ссылка лида", в поле "Какой режим добавления данных" выбрать "Добавить результат выборки", в поле "Выборка по объекту" указать "Файл и ссылка обращения" (например, возможно у вас будет другая таблица с хранимыми файлами, если вы не используете стоковую для обращений) и указать условие выборки (то есть фильтр по Id, где Id это идентификатор вашего обращения). Затем необходимо указать список полей которые нужно скопировать, в этих полях будут доступны данные по типу "Результат выборки. Версия" и так далее.

Приложу скриншоты одного такого работающего элемента.
Если возникнут вопросы можете писать в ЛС.

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

"Владимир Соколов" написал:

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


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

"Кисловский Михаил Андреевич" написал:Но возможно у Лида будут сторонние файлы, которые не должны быть в обращении.
Так что визуальная подмена деталей тут будет неуместна, на мой взгляд.

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

Кисловский Михаил Андреевич пишет:

Приложу скриншоты одного такого работающего элемента. Если возникнут вопросы можете писать в ЛС.

А можно скрин. У меня почему то не работает. Нужно из активности файл прикрепить в обращения. 

 

Владимир прав, плодить копии файлов без крайней необходимости не стоит. Но если всё же нужно копировать и стандартные механизмы работы с данными не подходят, можно сделать в базе хранимку с параметрами, осуществляющую копирование значения поля с файлом, а затем запускать её из C#-кода.

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

Добрый день!

Сталкивался ли кто-нибудь в миграции данных с TS 3.X на bpm'online 7.x с вопросом переносов файлов? Удалось это реализовать в более-менее автоматическом режиме?

Спасибо

Нравится

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

Здравствуйте.
Файлы и в той и в той системе хранятся в виде больших бинарных объектов. Процесс переноса не автоматизировали. Каждый случай рассматривается отдельно. Здесь можно абстрагироваться от продукта, в принципе. Есть две базы данных, содержащие некие сущности, которые нужно перенести. Возможно, в некоторой степени, поможет автоматизировать процесс утилита bdForge или аналогичная.

Понятно, что при доработках, да и без них есть нюансы. Но не каждый же раз изобретать велосипед для переноса tbl_Files?

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

Как я понимаю, в 3.X все файлы хранились в tbl_Files, а в bpm'online есть таблица File на каждую сущность (например, ContactFile).
А при этом есть еще таблица File. Что в ней записано?

В таблице, File bpm'online 7.x, не хранится ни какой информации (это наследие от bpm'online 5.x). Для Контактов файлы хранятся в таблице ContactFile, для Контрагентов в таблице AccountFile и т.д.

Пример простого переноса файлов из детали Файлы раздела Контакты (TS) в раздел Контакты ( bpm'online 7.x):

DECLARE @SupervisorBPMID UNIQUEIDENTIFIER = '410006E1-CA4E-4502-A9EC-E54D922D2C00';
DECLARE @SupervisorTSID UNIQUEIDENTIFIER = 'FFC4AABA-4882-41FC-8AC0-FC54D6DCFE93';
 
INSERT INTO [BPMonline_760_SalesOmnichannel_DemoInternal_Tereshchuk].[dbo].[ContactFile]
	([ContactId]
      ,[ProcessListeners]
      ,[Id]
      ,[CreatedOn]
      ,[CreatedById]
      ,[ModifiedOn]
      ,[ModifiedById]
      ,[Name]
      ,[Notes]
      --,[LockedById]
      --,[LockedOn]
      ,[Data]
      ,[TypeId]
      ,[Version]
      ,[Size]) 
SELECT 
	@SupervisorBPMID, 
	0, 
	NEWID(), 
	[CreatedOn], 
	@SupervisorBPMID/*CreatedByID*/, 
	[ModifiedOn], 
	@SupervisorBPMID/*ModifiedByID*/,
	[Link],
	ISNULL([Description], ''), 
	[FileData],
	case [ItemTypeID] 
		when '{39A5B367-4A7A-473E-8F74-26977CB6DB67}' then '529BC2F8-0EE0-DF11-971B-001D60E938C6'	-- Файл -> Файл
		when '{94A8A85B-7EAF-405C-900A-58DC0301EDC2}' then '539BC2F8-0EE0-DF11-971B-001D60E938C6'	-- Ссылка -> Ссылка
		when '{6D180D71-36C5-4278-8224-505B06559FD5}' then null										-- URL -> 
		when '{B48F1491-1460-4A18-A4A3-B13FD6EE5624}' then '549BC2F8-0EE0-DF11-971B-001D60E938C6'	-- Ссылка на папку -> Ссылка на объект
	end, 
	[Revision],
	[FileSize] 
FROM [TS_3.4.0.130_XRM_SD_Softkey_RUS].[dbo].[tbl_Files] WHERE [ID] IN (SELECT [FileID] FROM tbl_FileInContact WHERE [ContactID] = @SupervisorTSID)

Важно!
1. Идентификаторы пользователей Контактов TS, должны совпадать с идентификаторами пользователей Контактов bpm'online 7.x (в моем примере идентификаторы Supervisor не совпадают, и по этой причине привожу явно)
2. Любой импорт лучше выполнять через шлюзовые таблицы
3. В TS есть перечисление enm_FileTypes, а в bpm'online 7.x это таблица FileType, в запросе необходимо явно приводить типы (в моем примере это сделано через case)

Спасибо огромное за помощь!

И еще вопрос про опыт. Если перенос делать через Excel, то можно ли сохранить ID записей, чтобы использовать их для связывания?
А то однофамильцы, к которым надо привязать средства связи встречаются сплошь и рядом

Да, можно. Для этого необходимо вывести поле ID в раздел

Может быть, можно еще и связывать объекты (например, адрес с котнтактов) не по Имени-Фамилии контакта, а по его ID?

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

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

Задача:
Экспорт отчета 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 комментариев
Показать все комментарии

Доброго времени суток!
Собственно, задача состоит в следующем. Определенный тип договоров создается с обязательным полем, в котором указывается родительский договор. К одному родительскому договору могут прикреплены любое количество подчиненных договоров. Нужно: при прикреплении файла на деталь Файлы в подчиненных договорах, создавать такие же в родительском, т.е. на детали Файлы родительского договора должны быть все файлы всех подчиненных договоров. (естественно без дублей самих файлов в базе).
Как вариант решения - отслеживать добавление записей в разгрузочную таблицу tbl_FileInContract, и добавлять запись с ID родительского договора и ID файла. Правильный ли будет этот подход и каким образом его можно реализовать?

Нравится

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

Здравствуйте, Константин!

Алгоритм абсолютно правильный. Вам следует добавить свою функцию в function ProcessAfterAddOperations(AddedFileIDsArray) в скрипте scr_FilesDetailGridArea

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

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

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

Добавляю в свой раздел деталь Файлы. Делаю по примеру, как в разделе Контакты.
Деталь добавляется, файлы тоже добавляются и фильтруются по записям и успешно удаляются.
Но при добавлении файла возникает ошибка:

Эта ошибка появляется при каждом добавлении файла. После нажатия на кнопку ОК файл успешно добавляется.
Подскажите, пожалуйста, как избежать появления этой ошибки?

Нравится

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

Поставьте debugger в функцию btnAddFileOnClick скрипт scr_FilesDetailGridArea и подскажите после какой строчки и какой функции возникает сообщение об ошибке

Ошибка возникает в функции SetupGiveRightsByParentItemInsertSelectQuery(InsertSelectQuery)

строка: var RecordIDField = ItemRightsTable.Fields.ItemsByName('RecordID');
ItemRightsTable берется выше и как раз равен null.

Это таблица с правами, я правильно понимаю?
Где мне ее нужно указать?

Попробуйте следующий вариант:
В корневой таблице которая отвечает созданному вами разделу установите свойство
"Is Administrated By Records"
1

Алексей, спасибо, все заработало! :)

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

Недавно пользователи попросили добавить функцию копировать файлы вместе с карточкой библиотеки (по объективным причинам это необходимо).

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

/* Функция копирование детали файлы: */

function CopyFilesInItemDetail(SourceFileInItemDatasetCode, //источник
    DestinationFileInItemDatasetCode, //назначение
    SourceParentItemIDFieldName,
    DestinationParentItemIDFieldName, SourceItemID, DestinationItemID) {
    var SourceItemName = GetItemNameByParentItemIDFieldName(
                SourceParentItemIDFieldName);
        var DestinationItemName = GetItemNameByParentItemIDFieldName(
                DestinationParentItemIDFieldName);
        if (SourceItemName == DestinationItemName) {
                var Message = FormatStr(CopyItemDetailConfirmation, "Файлы");
        } else {
                var Message = FormatStr(CopyItemDetailFromItemToItem, "Файлы",
                        SourceItemName, DestinationItemName);
        }
        var SourceDataset = GetSingleItemByCode(SourceFileInItemDatasetCode,
                'FileDetailSource'); //источник
        SourceDataset.FetchRecordsCount = -1;
        var DestinationDataset = GetSingleItemByCode(
                DestinationFileInItemDatasetCode, 'FileDetailDestination'); //назначение
        DestinationDataset.FetchRecordsCount = -1;
        SourceDataset.DisableEvents();
        DestinationDataset.DisableEvents();
        try {
                ApplyDatasetFilter(SourceDataset, SourceParentItemIDFieldName, SourceItemID,
                        true);
                EnableDatasetFields(SourceDataset, true);
                EnableDatasetFields(DestinationDataset, true);
                SourceDataset.Open();
                if (IsDatasetEmpty(SourceDataset)) {
                        SourceDataset.Close();
                        return;
                }
                if (ShowConfirmationDialog(Message) != wmrYes) {
                        SourceDataset.Close();
                        return;
                }
                CopyTreeDetail(SourceDataset, DestinationDataset,
                        SourceParentItemIDFieldName, DestinationParentItemIDFieldName,
                        DestinationItemID);
        } finally {
                SourceDataset.EnableEvents();
                DestinationDataset.EnableEvents();
        }
}

/* Функция копирование детали файлы END */  

Затем, для wnd_LibraryEditScript подключил scr_DocumentUtils и прописал:

/* Функция копирование детали файлы: */

function ProcessCopyFilesDetail(Dataset) {
        var IsCopy = Self.Attributes('IsCopy');
        if (!IsCopy) {
            return;
        }
        var SourceFileInItemDatasetCode = 'ds_FileInLibrary';
        var DestinationFileInItemDatasetCode = 'ds_FileInLibrary';
        var SourceParentItemIDFieldName = 'LibraryID';
        var DestinationParentItemIDFieldName = 'LibraryID';
        var SourceItemID = Self.Attributes('SourceRecordID');
        var DestinationItemID = Dataset.Values('ID');
        CopyFilesInItemDetail(SourceFileInItemDatasetCode,
                DestinationFileInItemDatasetCode, SourceParentItemIDFieldName,
    DestinationParentItemIDFieldName, SourceItemID, DestinationItemID);
}

/* Функция копирование детали файлы END */

Но возникает ошибка, с которой не могу справиться:

"Необработанное исключение (требуется объект)"

и дебаггер выбрасывает на строчку SourceParentID = SourceParentIDDataField.Value;
в скрипте scr_DB.

Может кто поможет решить проблему? :smile:

Нравится

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

деталь продукты - это дерево
а деталь файлы - это не дерево , из-за этого и происходит ошибка
попробуйте реализовать как в задачах , копирование контактов
scr_TaskUtils (CopyTaskContacts)

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