Корректность работы детали "Участники" в объекте "Активности"
Добрый вечер, Коллеги!
Подскажите корректно ли работает деталь "Участники" в следующем кейсе:
Шаг1. При создании задачи автор указывает в поле "Ответственный" значение "Исполнитель1". В результате Система автоматически добавляет в деталь "Участники" запись с "Исполнителем1"
Шаг2. Автор заменяет в поле "Ответственный" значение "Исполнитель1". В результате Система автоматически добавляет в деталь "Участники" запись с "Исполнителем2" (удаляя "Исполнителя1") и "Автора"
---------------------------------------------------------------------
Вопрос почему Система ведет себя по-разному:
по логике для всех случаев должен быть один вариант:
либо автора задачи Система сразу добавляет в участники, либо никогда (только вручную или через созданный БП).
Сейчас реализован промежуточный вариант - такое поведение преследует какую-то логику или реализация содержит ошибку?
//подскажите куда надо смотреть, чтобы настроить кейс:
- автор при создании задачи добавляется в деталь "Участники"
либо
- автор при изменении ответственного не добавляется в деталь "Участники"
Понравилась ли вам эта идея?
Обратите внимание, что там ещё разная роль (видно, если вытянуть колонку):
Логика реализована во встроенном БП объекта Activity пакета Base:
public virtual void AddActivityParticipantToInsertedValues(Guid participantId, Dictionary<string, object> participantParams, bool overrideExistingParticipant) { var insertedValues = (InsertedValues as Dictionary<Guid, object>) ?? new Dictionary<Guid, object>(); InsertedValues = insertedValues; if (overrideExistingParticipant || !insertedValues.ContainsKey(participantId)) { insertedValues[participantId] = participantParams; } } public virtual bool OnActivitySaved(ProcessExecutingContext context) { SetActivityParticipantRightsOnSaved(); string typeColumnValueName = Entity.Schema.Columns.FindByName("Type").ColumnValueName; Guid typeId = Entity.GetTypedColumnValue<Guid>(typeColumnValueName); if (typeId == Terrasoft.Configuration.ActivityConsts.EmailTypeUId) { InitializeEmailParticipantHelper().InitializeParameters(Entity); AutoEmailRelationProceed(); InitializeEmailParticipantHelper().SetEmailParticipants(); } else { UpdateParticipantsByOwnerContact(); SynchronizeActivityOnSaved(); AutoEmailRelationProceed(); CreateActivityParticipantsFromInsertedValues(); } return true; } ... public virtual void RemoveEmailParticipants() { var recepientEmails = RecepientsEmailsForDelete as List<string>; if ((recepientEmails != null) && (recepientEmails.Count > 0)) { var queryParameters = recepientEmails.Select(item => new QueryParameter(item)).ToList(); new Delete(UserConnection) .From("ActivityParticipant") .Where("ActivityId").IsEqual(Column.Parameter(Entity.PrimaryColumnValue)) .And("ParticipantId").In( new Select(UserConnection) .Column("Id") .From("Contact") .Where("Email").In(queryParameters)).Execute(); } } public virtual void UpdateParticipantsByOwnerContact() { DeleteOldOwnerAndContactParticipants(); var participantRoles = ActivityUtils.GetParticipantsRoles(UserConnection); if ((newOwnerId != oldOwnerId) && (newOwnerId != Guid.Empty) && (newOwnerId != SenderId)) { AddActivityParticipantToInsertedValues( newOwnerId, new Dictionary<string, object> { {"RoleId", participantRoles["Responsible"]} }, true ); if (oldOwnerId != Guid.Empty) { var authorColumn = Entity.Schema.Columns.FindByName("Author"); if (authorColumn != null) { var authorId = Entity.GetTypedColumnValue<Guid>(authorColumn.ColumnValueName); AddActivityParticipantToInsertedValues( authorId, new Dictionary<string, object> { {"RoleId", participantRoles["Participant"]} }, false ); } } } if ((newContactId != oldContactId) && (newContactId != Guid.Empty) && (newContactId != newOwnerId) && (newContactId != SenderId)) { AddActivityParticipantToInsertedValues( newContactId, new Dictionary<string, object> { {"RoleId", participantRoles["Participant"]} }, false ); } }
Подробнее все вызовы этих функций см. там. Функции виртуальные, значит, их можно переопределить в этой схеме в своём пакете.
Зверев Александр,
Спасибо за ответ, то что нужно (+ отдельное спасибо за то, что обрати внимание на роль).
Еще остался вопрос, - все таки это корректная работа, что автор при создании задачи участников в деталь не добавляется, но добавляется только после изменения значения в поле "Ответственный"? Какой бизнес-смысл такого базового поведения Системы (я бы даже сказал не очевидного)
+ влияет ли роль "Участник" и "Ответственный" на какие либо процессы? На сколько я успел протестировать - нет.
По том, как надо правильнее, уточняю.
Посмотреть все места, где используется объект справочника ParticipantRole, можно выборкой по тексту C# и JS-схем.
select *, cast(source as varchar(max)) from sysschemasource where source like '%participantRole%' select *, cast(content as varchar(max)), (select name from sysschema where id = [SysSchemaId]) from sysschemacontent where content like '%participantRole%'
Как минимум, в Activity пакета Exchange для синхронизации встреч тоже добавляют именно «Участник»:
public virtual void SynchronizeParticipants() { if (string.IsNullOrEmpty(Entity.Sender) && string.IsNullOrEmpty(Entity.Recepient)) { return; } if (Entity.GetTypedColumnValue<Guid>("ActivityCategoryId") == ExchangeConsts.ActivityMeetingCategoryId) { var recepientsEmails = (List<string>)RecepientsEmails; Dictionary<Guid, string> contactDictionary = ContactUtilities.GetContactsByEmails(UserConnection, recepientsEmails); if (contactDictionary.Count > 0) { var participantRoles = ActivityUtils.GetParticipantsRoles(UserConnection); foreach (var contactId in contactDictionary.Keys) { AddActivityParticipantToInsertedValues( contactId, new Dictionary<string, object> { {"RoleId", participantRoles["Participant"]} }, false ); } var insertedValues = InsertedValues as Dictionary<Guid, object>; if (insertedValues != null) { UpdateContactAndAccountByParticipant(insertedValues.Keys.ToList()); } } Entity.SetColumnValue("Sender", string.Empty); Entity.SetColumnValue("Recepient", string.Empty); } }
Но это вставка, а не считывание.
Ещё константы ролей для писем используется в CommunicationPanelEmailSchema в условии фильтрации входящих/исходящих:
/** * Adds requested email type filters. * @private * @param {Terrasoft.FilterGroup} filters Emails query filters. * @param {Terrasoft.EntitySchemaQuery} esq Emails query. */ _addFilterByEmailType: function(filters, esq) { var roleColumn = "Role"; var emailType = this.get("EmailType"); if (!this.getIsFeatureEnabled("SharedMailboxes") || emailType === EmailConstants.emailType.DRAFT) { var currentUserContact = Terrasoft.SysValue.CURRENT_USER_CONTACT.value; filters.add("currentContactFilter", this.Terrasoft.createColumnFilterWithParameter( Terrasoft.ComparisonType.EQUAL, "Owner", currentUserContact)); } var participantRoles = ConfigurationConstants.Activity.ParticipantRole; switch (emailType) { case EmailConstants.emailType.INCOMING: this._addIncomingFilter(filters, roleColumn, [ participantRoles.To, participantRoles.CC, participantRoles.BCC ]); break; case EmailConstants.emailType.OUTGOING: this._addOutgoingFilter(filters, roleColumn, [participantRoles.From]); break; case EmailConstants.emailType.DRAFT: this._addDraftFilter(filters); break; default: break; } },
Но там из того же справочника другие значения ролей.
Передал им информацию, это ошибочное поведение платформы, будут исправлять в плановом порядке. Спасибо, что нашли.
Зверев Александр пишет:
Функции виртуальные, значит, их можно переопределить в этой схеме в своём пакете.
А не подскажите, как это сделать? Нам как раз надо заменить заполнение ActivityParticipants и раздачу прав в проекте, то есть, функции SetActivityParticipantRightsOnSaved, DeleteOldOwnerAndContactParticipants, UpdateParticipantsByOwnerContact
Владимир, я имел в виду создать в пакете Custom замещение объекта Activity и там в БП справа на вкладке «Методы» вписать свой вариант этой функции (можно с вызовом в начале или конце базового).
Например, в той же схеме Activity в пакете NUI так переопределяют PrepereSynchronizeSubjectRemindingUserTask, заданный в Base:
public override void PrepereSynchronizeSubjectRemindingUserTask(SynchronizeSubjectRemindingUserTask userTask, Guid contact, DateTime remindTime, bool active, Guid source) { base.PrepereSynchronizeSubjectRemindingUserTask(userTask, contact, remindTime, active, source); //...своя логика... }