Добрый день!

 

Реализовали функционал копирования деталей при копировании записи частично на примере существующего дополнения:

- в методе onSaved если режим  isCopy мы вызываем БП, в который отправляем конфиг с id старой\новой записи, название схемы и тд. Бизнес-процесс на основе заполненного справочника с колонками деталей создает новые связи с новой (скопированной записью).

 

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

Как лучше поступить в таком случае? Можно было бы реализовать это в событийном процессе базовой записи, но не очень понятно как в нем узнать, что сейчас происходит копирование, а не добавление. И почему вообще может возникать ошибка? Может быть в onSaved есть возможность доработки с ожиданием создания записи в бд? Заранее благодарю за ответы

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

Нравится

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

А данное дополнение не подошло под ваши задачи? https://marketplace.terrasoft.ru/app/copy-detail-records-creatio

Трефилов Павел Сергеевич,

частично оно удовлетворяет нашим требованиям, но не полностью. Поэтому я делал свой механизм, отчасти похожий на тот что используется в этом дополнении

Если это единичный случай, то я делал по другому:

Для страницы раздела переделать вызов метода copyRecord, в нем вызывать процесс, который делать поэтапно сначала делает копирование основной записи, а потом копирование записей деталей. К сожалению в БП нету элемента "сделать копию". Поэтому приходилось делать Читать данные - Добавить данные (режим одна запись) - Сохранить в id новой записи в переменную - Добавить данные в деталь (результат выборки) - открыть запись.

		methods: {
			copyRecord: function(primaryColumnValue) {
				this.runCustomCopyProcess(primaryColumnValue);
			},
 
			runCustomCopyProcess: function(primaryColumnValue){
				var args = {
					sysProcessName: "UsrCopySpecificationCustomer",
					parameters: {
						specificationsId: primaryColumnValue
					}
				};
				ProcessModuleUtilities.executeProcess(args);
			},
		}

Это все можно сделать и через isCopy, но там надо отловить момент, когда основная запись уже сохранилось и тогда запускать копирование детали, пример есть в InvoiceSection, правда код крайне замороченный, плюс там еще и вьюшки задействованы. По мне так проще через БП сделать, как у меня, пусть и не очень "красиво".

Трефилов Павел Сергеевич,

В плане копирования связей проблем нет -- сделали БП, там все работает. Проблема скорее в отлавливании момента, когда запись копии основной страницы уже создалась. Казалось бы, у нас для этого есть onSaved -- бери и делай. Но нет, не всегда в момент срабатывания onSaved запись уже создана в бд видимо...

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

При выделении заказа в разделе "Заказы" появляется кнопка "Копировать. Она создает новый заказ и переносит только основные поля. 

Где можно найти этот механизм, чтобы добавить в него еще копирование продуктов и цен?

Нравится

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

Можно убрать копирование поля, сняв в объекте у него признак копирования. Но тогда цена будет 0.



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

Возможно, с этим дополнением будет легче - https://marketplace.terrasoft.ua/app/copy-detail-records-creatio

Необходимо переопределить кнопку копировать и написать свой код который будет к примеру отправлять id заказ в ваш процесс или веб сервис и там прописать свою логику копирования.

Владимир Соколов,

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

Появилась другая проблема, что он копирует подчистую, то есть, старые цены

Как можно поправить эту ситуацию, чтобы при копировании автоматически,

старые цены обновлялись на текущие?

Можно убрать копирование поля, сняв в объекте у него признак копирования. Но тогда цена будет 0.



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

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

Добрый день, мне надо. что бы при создании записи в разделе копировались значения и родительской записи, так как полей больше 70

Есть деталь, которая является раделом, т.е на ней отображены отфильтрованные записи раздела

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

Нравится

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

Да, возможно. Сделайте БП, запуск по записи. Читать родительскую запись, далее добавить запись в раздел и открыть страницу на редактирование только что созданной записи. У меня так реализовано добавление доп.соглашения к договору. 

Можно развить дальше и сделать отдельную кнопку для запуска процесса.

Алексей Следь,

мне надо что бы все 100+ полей копировались одной коллекцией, добавлять вручную такое мне не особо по душе

Dima Avdoshin,

Не понял. Один раз настроить в БП элемент добавить данные и все. Все 100+ полей будут копировать автоматически при создании новой записи. Если сложно настроить элемент добавить данные, то можно все сделать добавление данных скриптом в том же процессе. Можно через InsertSelect

Алексей Следь,

InsertSelect не вызвет событийную модель, что не есть хорошо.

Dima Avdoshin,

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

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

А все колонки из родительской скопирует базовая логика системы:

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

Владислав Литвинчук пишет:

InsertSelect не вызвет событийную модель, что не есть хорошо.

Если проблема только в этом, можно создавать Entity, наполнять её поля и затем вызывать Save. Или, как изначально предложили, средствами стандартных элементов БП для работы с данными.

 

По изначальному вопросу темы:

Вы хотите копировать из одноимённых полей одного объекта в другой?

А то, если просто создать копию записи, то в реестре есть кнопка копирования записи, при нажатии на неё создаётся новая запись с заполненными полями, у которых в объекте включена галка «Копировать данные при копировании записи».

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

то в реестре есть кнопка копирования записи, при нажатии на неё создаётся новая запись с заполненными полями, у которых в объекте включена галка «Копировать данные при копировании записи».

Да именно это мне нужно, каким образом я могу вызвать ее программно?

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

можно пример пожалуйста

Сходу нашёлся пример только из интерфейса 5.Х в базовой карточке. От него можно отталкиваться, выкинув лишнее.

row = dataSource.Rows[0].Clone() as Terrasoft.Core.Entities.Entity;
Guid currentUserContactId = Page.UserConnection.CurrentUser.ContactId;
EntityPrimaryColumnValue = Guid.NewGuid();
row.SetColumnValue(primaryColumnName, EntityPrimaryColumnValue);
row.SetColumnValue("CreatedOn", DateTime.Now);
row.SetColumnValue("CreatedById", currentUserContactId);
row.SetColumnValue("ModifiedOn", DateTime.Now);
row.SetColumnValue("ModifiedById", currentUserContactId);
var columnNames = new List<string>();
foreach (var column in row.Schema.Columns) {
	if (column.HasDefValue && 
		((column.IsLookupType || column.IsMultiLookupType) &&
		column.ReferenceSchema.PrimaryDisplayColumn != null) &&
		!columnNames.Contains(column.Name)) {
		columnNames.Add(column.Name);
	}
}
row.LoadLookupDisplayValues(columnNames);
dataSource.Insert(row);

У объекта Entity есть метод .Clone() (или вызываемый им же конструктор Entity(Entity source)). Запускаем его, получаем новый объект в памяти. При необходимости заполняем текущими датой и пользователем стандартные 4 поля, затем те поля, значения которых в Вашей логике нужно поменять относительно образца. Все остальные поля, у которых в дизайнере есть галочка, скопировались автоматически. Id, естественно, будет уже новый.

Цикл из примера не нужен, ведь поля для отображения справочников нас сейчас не интересуют. И в конце запускаем у своего Entity метод .Save(), чтобы эта запись из памяти попала в базу. Кажется, ничего не упустил.

 

Но это всё на уровне C#-скрипта в процессе. Если надо в JS-логике, подобно кнопке копирования, нужно смотреть, как она устроена.

 

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

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

Добрый день.
Если я копирую процесс (кнопка "Копировать диаграмму") который находится в пакете "MyPackage", то копия создается в пакете "Custom". Даже если в системной настройке CurrentPackageId установлен "MyPackage".

Является ли данное поведение корректным?
И есть ли возможность при создании копии указывать в какой пакет создавать эту копию?
Версия 7.10.0.1742

Нравится

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

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

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

Насчет корректности такого поведения системы (копирования в Custom). Логично копировать в тот пакет, который указан пользовательским. Вы пишите, что сменили значение настройки CurrentPackageId, попробуйте изменить значение настройки CustomPackageUId, после вылогиниться и потом зайти и проверить, куда будет скопирована диаграмма.

"Алла Савельева" написал:В новой диаграмме, которая создалась после копирования, нужно перейти на закладку Settings (Настройки) и в поле Package (Пакет) указать нужное значение (см. прикрепленный файл).

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

"Алла Савельева" написал:
...
попробуйте изменить значение настройки CustomPackageUId
...

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

Просьба к сотрудникам Террасофт:
Может стоит указать об этой особенности копирования диаграмм в документации или исправить код который смотрит на CustomPackageUId вместо CurrentPackageId?

На самом деле в документации информация об этой настройке есть на Академии по ссылке: https://academy.terrasoft.ru/documents/technic-sdk/7-9/paket-custom, хотя, как по мне, объяснение отличий не очень очевидно :confused:

Информацию по работе с пакетами можно найти тут: https://academy.terrasoft.ru/documents/technic-sdk/7-9/rabota-s-paketami

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

Нужно разработать логику которая бы копировала и данные детали раздела.
Есть такой код isCopyMode

onEntityInitialized: function() {
                                if (this.isAddMode() || this.isCopyMode()) {
//код
}
}

Но как узнать данные источника откуда копируется раздел ?

Нравится

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

Если это isCopyMode то id от кого скопировались узнать можно так:
this.get("SourceEntityPrimaryColumnValue")
Если isAddMode, то понятно, что нет никакого источника.

Максим спасибо.
Буду делать копирование так

onEntityInitialized: function() {
				if (this.isCopyMode()) {
 
this.get("SourceEntityPrimaryColumnValue"); //id источника
//код копирования
 
				}

вопрос...как я понимаю пока еще нет же созданной записи в БД?

"Юсупов Марат" написал:как я понимаю пока еще нет же созданной записи в БД?

Все верно, данной записи еще нет в бд, но вы можете вызвать:
this.save({silent:true}) что сохранит данную запись в бд, не закрывая карточку. После чего можно будет добавлять в неё и записи деталей.

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

Доброго дня!
Столкнулся со след. задачей:
Имеется 2 раздела: "Заказы" и "Инженерная спецификация"
Оба раздела имеют свою древовидную деталь "Продукты"
Мне необходимо скопировать выделенные продукты из раздела "Инженерная спецификация" в раздел "Заказы". Копироваться должны только определенные поля.
Подскажите пожалуйста, как это можно реализовать?

Нравится

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

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

У каждого грида есть свойство SelectedIDs - возвращаемое массив идентификаторов выделенных записей. Зная идентификатор записи, можете выполнить обновление продуктов в древовидном реестре другого реестре. Обновление можно реализовать несколькими способами:

  1. 1. Используя датасет
  2. 2. Используя запрос на обновление
  3. 3. Используя хранимую процедуру

Рекомендую использовать первый способ, выполнить обновление через датасет.
Как за пример, можете взять логику обновления данных детали [Средства связи] раздела [Контрагент] реализованной в функции ActualizeCommunication сервиса scr_Account.

Cпасибо, сейчас попробую!

Можно еще посмотреть реализацию копирования дерева продуктов в scr_DocumentUtils...
Функция CopyOfferingInItemDetail. И далее из нее вызовы...

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

Здравствуйте!
Возникла проблема при копировании записей.
Использую следующий конструктор:
var newEntity = new Entity (entity);
Запись корректно создается, однако события объекта не срабатывают, в чем может быть проблема?

Полный код приведен ниже:

private void copyRouteDetail(Guid TemplateId, Guid TransRequestId) {
        EntitySchema schema = UserConnection.EntitySchemaManager.GetInstanceByName("SxRouteDetailTransRequest");
        EntitySchemaQuery esq = new EntitySchemaQuery(schema);
        esq.AddAllSchemaColumns();
        esq.UseAdminRights = false;
        esq.Filters.Add(esq.CreateFilterWithParameters(FilterComparisonType.Equal,
                                                        "SxRouteOptions", TemplateId));
        EntityCollection entities = esq.GetEntityCollection(UserConnection);
         foreach (Entity entity in entities)
        {
                var newEntity = new Entity (entity);
                newEntity.SetColumnValue("SxRouteOptionsId", null);
                newEntity.SetColumnValue("SxTransRequestId", TransRequestId);
                newEntity.UseAdminRights = false;
                newEntity.Save(false);
        }
}

Нравится

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

Здравствуйте, данный вопрос будет решён в рамках Вашего обращения №0300267

"Пащенко Александр Сергеевич" написал:Запись корректно создается, однако события объекта не срабатывают, в чем может быть проблема?

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

я бы рекомендовал внимательно проанализировать все бизнес-процессы выполняемые в сохраняемом Entity, внимательно проанализировать сначало Глазами, а потом внимательно проанализировать в Дебагере, что происходит в вашей базе данных при сохранение, и найти место где возникает исключение, при котором запись создается, но не выполняются события.

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

Михаил, все процессы процессы построены корректно и работают стабильно.
Процитирую ответ техподдержки:
"Данное поведение проявляется по причине того что, при использования данного конструктора класса Entity свойства создаваемого объекта отвечающие за вызов событий проставляются как false. К сожалению, изменить данные свойства после создания объекта нельзя.

Данную задачу можно решить следующим образом:

var userConnection = context.UserConnection;
var schema = UserConnection.EntitySchemaManager.GetInstanceByName("Account");
var newEntity = schema.CreateEntity(UserConnection);
newEntity.SetDefColumnValues();
//код установки значений колонок объекта
newEntity.Save();

Упростить задачу копирования значений колонок из одного объекта в другой можно используя метод public IEnumerable GetColumnValueNames(), который возвращает имена колонок объекта. Затем перебирая в foreach результат данного метода скопировать значения колонок."

При отладке, единственная разница, которую нашел - при использовании конструктора
var newEntity = new Entity(oldEntity)
у newEntity.Process=null,
у oleEntity.Process = не nulll, а ссылка на метод.

Михаил, все процессы процессы построены корректно и работают стабильно.
Процитирую ответ техподдержки:
"Данное поведение проявляется по причине того что, при использования данного конструктора класса Entity свойства создаваемого объекта отвечающие за вызов событий проставляются как false. К сожалению, изменить данные свойства после создания объекта нельзя.

Данную задачу можно решить следующим образом:

var userConnection = context.UserConnection;
var schema = UserConnection.EntitySchemaManager.GetInstanceByName("Account");
var newEntity = schema.CreateEntity(UserConnection);
newEntity.SetDefColumnValues();
//код установки значений колонок объекта
newEntity.Save();

Упростить задачу копирования значений колонок из одного объекта в другой можно используя метод public IEnumerable GetColumnValueNames(), который возвращает имена колонок объекта. Затем перебирая в foreach результат данного метода скопировать значения колонок."

При отладке, единственная разница, которую нашел - при использовании конструктора
var newEntity = new Entity(oldEntity)
у newEntity.Process=null,
у oleEntity.Process = не nulll, а ссылка на метод.

"Пащенко Александр Сергеевич" написал:Данную задачу можно решить следующим образом:

var userConnection = context.UserConnection;
var schema = UserConnection.EntitySchemaManager.GetInstanceByName("Account");
var newEntity = schema.CreateEntity(UserConnection);
newEntity.SetDefColumnValues();
//код установки значений колонок объекта
newEntity.Save();

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

так техническая поддержка вам предложила верный вариант решения вашей проблемы. Чем он вам не нравиться? что не устраивает?

Мне нужно сделать точную копию записи, в которой более 70 колонок, изменив всего 1 значение. Использовать для этого указанный выше конструктор считаю более целесообразным, но он некорректно работает. О варианте перебора всех колонок я знал. Сюда ответ продублировал на случай, если кому-то понадобится еще.

Спасибо за отклик!

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

вы свою задачу можете вообще решить иструментами бизнес-процесса, и поидее это будет правильно. Подглядеть к примеру можно в бизнес-процесс  CreateInvoiceFromOrder . В данном бизнес процессе как раз происходит копирование продуктов из Заказа в Счет. Я бы пошел по данному пути.

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

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

Нравится

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

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

Если Вам не трудно, прошу Вас уточнить Ваш вопрос скриншотами.

Если я правильно понял, то Вас интересует как передать значение со страницы проекта в страницу детали, чтобы рассчитать значение полей. Это можно сделать с помощью messages.
1. В объект messages проекта добавить SUBSCRIBE. В объект messages детали добавить PUBLISH.
2. На init проекта подписаться на сообщение
this.sandbox.subscribe("GetSomeInfoFromDetail", function(argument) {
return this.someFunctionUsingArgument();
}, this, ["key"]);
3. На детали, когда Вам нужно получить значение с проекта сделать sandbox.publish
var result = this.sandbox.publish("GetSomeInfoFromDetail", valueToSend, ["key"]);

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

Спасибо, Вы очень помогли :smile:

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

В этом блоге хочу рассказать о развитии 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.

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

Заметил такую вещь, что при копировании записи (например, счета или договора) копируются также поля синхронизации с 1С (UID1C, Object1C, Code1C). Из-за этого рушится система синхронизации с 1С для таких записей с одинаковыми полями.
Начал копать в этом направлении:
1. Копирование записи реализуется функционалом wnd_BaseGridArea:

CopyGridAreaData(Self, BaseGridArea);

2. Эта функция в скрипте scr_BaseGridAreaUtils

А дальше завис. Можно подсказать, где именно та функция, которая копирует поля записи? Чтобы можно было там сделать исключение для полей синхронизации с 1С.

Нравится

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

Попробуйте в соответствующем Dataset снять "галочку" копировать для этих полей.

А там галочки и так не стоят не стоят (((

Копирование полей при копировании записей производится в ядре системы. Для того, чтобы указать, какие колонки следует/не следует копировать, в наборе данных для соответствующих колонок нужно изменить значение параметра «Копирование поля». Если галочка не стоит, то и поле не будет копироваться.
В Вашем случае, при интеграции с 1С, указанные поля добавляются в таблицу, но по умолчанию не добавляются в набор данных. Добавили ли Вы их в набор данных? Если да, то убрали ли галочки напротив параметра «Копирование поля»? Если таких полей в наборе данных нет, то добавьте их и снимите галочки копирования.
Если же у Вас в наборе данных присутствуют указанные поля, для них сняты галочки копирования, но копирование все равно происходит, то Вам следует сделать скриншоты параметров этих полей набора данных, указать версию бинарных файлов и используемый Вами продукт, ОС, тип БД, экспортировать сервисы таблицы, запроса на выборку и набора данных и прислать все эти данные для более детального рассмотрения проблемы. В последнем случае ситуация нетипична.

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