AXForum  
Вернуться   AXForum > Блоги > CRM, SharePoint и Черная Магия
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск

Добро пожаловать в мой блог! Изначально он не задумывался как блог CRM разработчика, но жизнь сама внесла нужные коррективы. Тут я публикою все свои наблюдения относительно обозначенных в заголовке систем. Если Вы найдете в нем что-то интересное для Вас, как для заказчика, то буду рад сотрудничать с Вами! В моей компетенции 100% задач по MS CRM 3.0/4.0/2011:
  • Консалтинг
  • Проектирование
  • Разработка
  • Обучение


MVP 2010, 2011
Оценить эту запись

Как создать звонок или встречу для кастомного объекта

Запись от Артем Enot Грунин размещена 28.08.2013 в 14:46
Обновил(-а) Артем Enot Грунин 07.10.2013 в 10:07
Теги activity, fixrm, unsupport

В одном из своих прошлых постов, я писал про сходства и отличия стандартных и кастомных типов действий: CRM 2011 Custom Activitys - Особенности. Тогда я коснулся только верхнеуровневых объектов действий, но не затрагивал такой интересный "подобъект" как "Стороны действия" (activity party). Что такое стороны действия, вы можете подробно почитать в SDK. Если кратко, все действия (кроме задачи) связывают несколько сторон, или участников. Например, действие «Электронная почта» имеет «Получателей» и «Отправителя», встреча имеет «Участников» и «Организатора», и т.д. Все разновидности участников называются Сторонами действия. Кроме того, стороны привязываются к особым системным типам полей множественного выбора "PartyList". Это и есть те самые поля "Получатель" (почта), "Обязательные участники" (встреча) и пр.

Впрочем, оставим этот ликбез и перейдем, собственно, к задаче. Недавно мой хороший знакомый и недавний коллега по MS Андрей Слепицкий обратился ко мне с вопросом: можно ли использовать кастомные объекты как стороны действия? Например, мы ввели в систему отдельную сущность Партнер и хотим позвать партнера на встречу. Сперва задача показалась мне простой: в чем проблема - разрешить действия в настройках объекта?:

Нажмите на изображение для увеличения
Название: Settings.png
Просмотров: 1229
Размер:	15.5 Кб
ID:	341

Однако, все оказалось сложнее. К сожалению, система позволяет выбор кастомного объекта только в поле "В отношении", но не в других полях, таких как "Обязательные участники" встречи. Небольшое исключение составляет форма Электронной почты. Если отметить вторую галочку: Sending e-mail, система позволит выбирать кастомный объект в поле "Получатель" (to) на форме электронной почты. Но как же быть с остальными полями?

Для того чтобы исследовать феномен, я решил провести зловещий эксперимент. Для этого я модифицировал пример создания встречи из SDK Sample: Book an Appointment чтобы добавить в список участников встречи свой кастомный объект:

X++:
              String crmconnection = "Server=http://crm/FixRM";
              CrmConnection connection = CrmConnection.Parse(crmconnection);
              OrganizationService service = new OrganizationService(connection);
  
              WhoAmIRequest userRequest = new WhoAmIRequest();
              WhoAmIResponse userResponse = (WhoAmIResponse) service.Execute(userRequest);
  
              // Create the ActivityParty instance.
              ActivityParty me = new ActivityParty
              {
                  PartyId = new EntityReference(SystemUser.EntityLogicalName, userResponse.UserId)
              };
  
              ActivityParty customparty= new ActivityParty
              {
                  //
                  PartyId = new EntityReference("fixrm_customparty", new Guid("6793AD07-E70E-E311-8E30-080027004A52"))
              };
  
              // Create the appointment instance.
              Appointment appointment = new Appointment
              {
                  Subject = "Test Appointment",
                  Description = "Test Appointment created using the BookRequest Message.",
                  ScheduledStart = DateTime.Now.AddHours(1),
                  ScheduledEnd = DateTime.Now.AddHours(2),
                  Location = "Office",
                  RequiredAttendees = new ActivityParty[] { me, customparty},
                  Organizer = new ActivityParty[] { me }
              };
  
              // Use the Book request message.
              Guid id = service.Create(appointment);
p.s. Для простоты тут я использую метод Create а не Book.

Результат эксперимента показал следующее:
  • Встречу МОЖНО создать с кастомным участником!
  • НУЖНО включить для объекта Sending e-mail, иначе вы получите ошибку "Invalid party type code" при попытке добавить его как участника
  • НЕ ТРЕБУЕТСЯ разрешать активности (Activities) для объекта, чтобы можно было добавить кастомного участника
Последний факт меня несколько удивил, с другой стороны, это, возможно, логично.

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

Нажмите на изображение для увеличения
Название: appointment.png
Просмотров: 1059
Размер:	93.1 Кб
ID:	342

Трюк заключается в том чтобы средствами JS DOM изменить атрибуты lookuptypes, lookuptypeIcons и lookuptypenames у нужного lookup контрола при загрузке формы. Как это часто бывает с ансаппортом, непонятно на что влияет последний атрибут - все работает и без него, однако его я для порядка тоже привожу в соответствие.

X++:
if (typeof (FixRM) == "undefined")
  { FixRM = { __namespace: true }; }
  
  /*
  Events
  FixRM.CustomActivityParty.AddPartyTypeOnLoad
  */
  
  FixRM.CustomActivityParty = {
      AddPartyTypeOnLoad: function (settings)
      {
          for (var setting in settings)
          {
              var parties = settings[setting];
  
              for (var i = 0; i < parties.length; i++)
              {
                  var party = parties[i];
  
                  this.AddPartyType(setting, party.otc, party.schema, party.schemaName);
  
                  if (party.isDefault == true)
                  {
                      this.SetDefaultParty(setting, party.otc, party.DefaultViewId);
                  }
              }
          }
      },
  
      AddPartyType: function (name, otc, schema, schemaName)
      {
          function ApendAttributeValue(node, name, separator, value)
          {
              var attribute = node.getAttribute(name);
              var attributeValues = attribute.split(separator);
              attributeValues.push(value);
  
              attribute = attributeValues.join(separator);
              node.setAttribute(name, attribute);
          }
  
          var lookup = document.getElementById(name);
          if (lookup && lookup.attributes)
          {
              ApendAttributeValue(lookup, "lookuptypes", ",", otc);
  
              var icoPath = Xrm.Page.context.prependOrgName("/_Common/icon.aspx?cache=1&iconType=GridIcon&objectTypeCode=" + otc);
              ApendAttributeValue(lookup, "lookuptypeIcons", ":", icoPath);
  
              if (schema && schemaName)
              {
                  var lookuptypename = schema + ":" + otc + ":" + schemaName;
                  ApendAttributeValue(lookup, "lookuptypenames", ",", lookuptypename);
              }
          }
      },
  
      SetDefaultParty: function (name, otc, view)
      {
          var lookup = document.getElementById(name);
          if (lookup && lookup.attributes)
          {
              lookup.setAttribute("defaulttype", otc);
              if (view)
              {
                  lookup.setAttribute("defaultViewId", view);
              }
          }
      },
  
      __namespace: true
  };
Второй неприятный момент заключается в том, что данный функционал активно использует числовой ObjectTypeCode, который, вообще-то deprecated и в следующих версиях должен быть полностью заменен на строковое свойство LogicalName. Исходя из этого, опасно кодировать подобную функциональность непосредственно в тексте программы. Для того чтобы облегчить переносимость, реализация принимает параметры из настроек обработчика события формы:

Нажмите на изображение для увеличения
Название: event.png
Просмотров: 1170
Размер:	28.3 Кб
ID:	343

Настройки задаются как строка JSON:
X++:
{
   1: [     ],
   2: [     ]
}
Сами типы участники задаются в формате:
X++:
{
  otc: <  >,
  schema: <  >,
  schemaName: <  (        REST)>,
  isDefault: <          .  >,
  DefaultViewId: <      .  ,       >
}
Приятно удивил тот факт, что система автоматически приводит текст JSON параметра к JS объекту, поэтому нет необходимости парсить его самостоятельно.

Заключение
Ни я ни Андрей не смогли выяснить, является ли это решение поддерживаемым хотя бы частично. Визуальная часть - не поддерживается абсолютно! Остается вопрос, можно ли делать такие вещи через вызовы SDK. На мой взгляд это ограничение - не более чем недосмотр разработчиков. Время покажет!
Вложения
Тип файла: zip FixRMCustomActivityParty_1_0_0_0.zip (21.0 Кб, 999 просмотров)
Размещено в CRM
Просмотров 27313 Комментарии 0
Всего комментариев 0

Комментарии

 


Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 08:12.