Копирование контактов при создании копии задачи в расписании
Доброго времени суток всем!
Уверен, не раз перед Вами вставала задача копирования подчиненных записей вместе с копированием родительской!
Вот и я недавно реализовал подобный функционал. Конечно, пошел сначала с самого сложного и громоздкого решения: определил новый датасет-источник, отфильтровал его по ID родительской записи. Объявил новый датасет - "прототип" копии. В цикле прошел по источнику, и скопировал все поля (благо их не много их было, всего лишь десяток ) из источника в "прототип". После каждого такого прохода постил датасет "прототипа".
Посмотрел потом на всю это красоту в полторы страницы кода, и подумал: "А не сделать ли мне все это еще красивей?". И сделал...
Покопавшись немного в конфигурации, открыл для себя удивительную вещь! Разработчики уже почти все до меня придумали! ДЛЯ меня! Бери и пользуйся!
Вот базовый сервис Common\Library\scr_DocumentUtils, а в нем готовый метод: function CopySimpleDetail( ... тут мы чего-то принимаем ) - запомним это.
Итак, конкретная задача: копировать контакты задачи, при копировании самой задачи путем перетаскивания ее графического элемента на контроле "Расписание задач". Т.е.: заходим в расписание, зажимаем CTRL и цепляем мышкой какую-нибудь задачку. Тянем ее в удобное или нужное нам место, и там отпускаем. При таком действии, контакты задачи не будут скопированы. Соответственно новую копию у себя в расписании увидит только ее Ответственный. Но если я не ответственный, а автор. И тоже хочу новую задачку видеть и контролировать?
Выход есть. Идем в админку. В модуле задач, находим группу сервисов ShedulerArea - где-то здесь находится то, что нам нужно.
Открываем Tasks\General\SchedulerArea\wnd_SchedulerArea, становимся в нем на элемент ScheduleControl и смотрим в список событий, которые им поддерживаются: находим OnCopyEvent.
Переходим по событию, и попадаем в обработчик: сервис Tasks\General\SchedulerArea\scr_SchedulerArea, функция function CopyEvent(Event).
Здесь, пробежав быстренько по коду глазами, сразу видим что к чему: вот у нас датасет новой задачки обяавился
А вот мы его запостили и обновили деталь:
RefreshDataset(SchedulerArea.EventsDataset);
Вот между постом и обновлением-то, давайте вставим наше копирование. Вернемся к функции function CopySimpleDetail( ...) - по принимаемым аргументам сразу видно что мы ей должны "подкинуть". Давайте же зададим ей входные переменные:
//Датасет-источник. Получаем его, вызвав базовый метод.
ApplyDatasetFilter(SourceDataset, 'TaskID', SourceRecordID, true);
//Источник отфильтруем по родительскому полю.
var SourceParentItemIDFieldName = 'TaskID';
//Ну, тут без лишних слов ясно, чем мы здесь занимаемся...
var DestinationDataset = Services.GetNewItemByUSI('ds_ContactInTask');
//Датасет получатель - объект. Вызываем метод объекта ядра (Services), который который умеет создавать клоны датасетов.
var DestinationParentItemIDFieldName = 'TaskID';
var DestinationItemID = Dataset.ValAsGUID('ID');
//Тут тоже все прозрачно и понятно.
На этом подготовительные работы закончены. Переходим к самому интересному: добавим немного логики - "а не спросить ли нам пользователя, точно ли он хочет скопировать контакты?" - в старых добрых традициях Windows , очень природно и естественно в работе с приложением.
А в каком случае спрашивать-то будем? Можно всегда. Но мне важно было в случае, если Автор и Ответственный разные люди. Совместив вопрос пользователю и условие на выполнение получим:
//подготовительная прелюдия...
//вызов функции копирования:
CopySimpleDetail(SourceDataset, DestinationDataset,
SourceParentItemIDFieldName, DestinationParentItemIDFieldName,
DestinationItemID)
}
Не хватает еще последней детали: сервису Tasks\General\SchedulerArea\scr_SchedulerArea ничего не известно о таком замечательном методе как CopySimpleDetail() - его надо подключить к scr_SchedulerArea из Common\Library\scr_DocumentUtils.
Ну, теперь можно собрать все воедино! Новое "лицо" обработчика события:
var Dataset = SchedulerArea.EventsDataset;
Dataset.DisableGettingDisplayValues();
try {
var SourceRecordID = SchedulerArea.EventsDataset.ValAsStr('ID');
try {
Dataset.Copy(SourceRecordID);
} catch (E){
ShowWarningDialog(E.message);
Dataset.Close();
return;
}
Dataset.ValAsGUID('ID') = Connector.GenGUID();
Dataset.Values('StartDate') = Event.Start;
Dataset.Values('DueDate') = Event.Finish;
Dataset.Post();
var Result = ShowConfirmationDialog('Копировать контакты задачи?')
if ((Dataset.Values('AuthorID') != Dataset.Values('OwnerID')) && (Result == mrYes)) {
var SourceDataset = GetSingleItemByCode('ds_ContactInTask');
ApplyDatasetFilter(SourceDataset, 'TaskID', SourceRecordID, true);
var SourceParentItemIDFieldName = 'TaskID';
var DestinationDataset = Services.GetNewItemByUSI('ds_ContactInTask');
var DestinationParentItemIDFieldName = 'TaskID';
var DestinationItemID = Dataset.ValAsGUID('ID');
CopySimpleDetail(SourceDataset, DestinationDataset,
SourceParentItemIDFieldName, DestinationParentItemIDFieldName,
DestinationItemID)
}
RefreshDataset(SchedulerArea.EventsDataset);
} finally {
Dataset.EnableGettingDisplayValues();
}
}
Чем не красота?
Приятной Вам работы, творческих успехов!
Паша, всё хорошо. Но что будет если контактов по задаче будет хотя бы 50... или 100... а если 200?... ну ладно 500 ) Интересно за сколько отработает данное копирование?
Если не нужны события датасета, то необходимо писать просто insert на основе select. Копирование происходит мгновенно. Реализация 20 мин.
Ок, Спасибо за замечание, Иван! учту.
ну, для компаний средних размеров, с количеством пользователей до 20, надеюсь, подойдет :)
При необходимости усовершенствуем.
Паша, для большинства наших клиентов вопрос производительности очень важен!
Может insert'ами на основе select? :wink:
В идеале бы переписать функцию копирования детали под динамически создаваемый InsertSelect, аналогично Update-запросу в функции UpdateRecord.