![]() |
#1 |
Участник
|
axforum blogs: Как создать звонок или встречу для кастомного объекта
Источник: http://axforum.info/forums/blog.php?b=421
============== В одном из своих прошлых постов, я писал про сходства и отличия стандартных и кастомных типов действий: CRM 2011 Custom Activitys - Особенонсти. Тогда я коснулся только верхнеуровневых объектов действий, но не затрагивал такой интересный "подобъект" как "Стороны действия" (activity party). Что такое стороны действия, вы можете подробно почитать в SDK. Если кратко, все действия (кроме задачи) связывают несколько сторон, или участников. Например, действие «Электронная почта» имеет «Получателей» и «Отправителя», встреча имеет «Участников» и «Организатора», и т.д. Все разновидности участников называются Сторонами действия. Кроме того, стороны привязываются к особым системным типам полей множественного выбора "PartyList". Это и есть те самые поля "Получатель" (почта), "Обязательные участники" (встреча) и пр. Впрочем, оставим этот ликбез и перейдем, собственно, к задаче. Недавно мой хороший знакомый и недавний коллега по MS Андрей Слепицкий обратился ко мне с вопросом: можно ли использовать кастомные объекты как стороны действия? Например, мы ввели в систему отдельную сущность Партнер и хотим позвать партнера на встречу. Сперва задача показалась мне простой: в чем проблема - разрешить действия в настройках объекта?: Однако, все оказалось сложнее. К сожалению, система позволяет выбор кастомного объекта только в поле "В отношении", но не в других полях, таких как "Обязательные участники" встречи. Небольшое исключение составляет форма Электронной почты. Если отметить вторую галочку: 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. Результат эксперимента показал следующее:
Иными словами, использовать кастомные объекты в действиях можно, единственная проблема - это как-то добавить эту возможность в пользовательский интерфейс. И вот тут начинается небольшой, но грязный unsupport… Ниже к посту приложено неуправляемое решение, которое реализует искомую функциональность. Трюк заключается в том чтобы средствами 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. Исходя из этого, опасно кодировать подобную функциональность непосредственно в тексте программы. Для того чтобы облегчить переносимость, реализация принимает параметры из настроек обработчика события формы: Настройки задаются как строка JSON: X++: { имя поля1: [ массив добавляемых типов участников ], имя поля2: [ массив добавляемых типов участников ] } Сами типы участники задаются в формате: X++: { oct: , schema: , schemaName: , isDefault: , DefaultViewId: } Приятно удивил тот факт, что система автоматически приводит текст JSON параметра к JS объекту, поэтому нет необходимости парсить его самостоятельно. Заключение Ни я ни Андрей не смогли выяснить, является ли это решение поддерживаемым хотя бы частично. Визуальная часть - не поддерживается абсолютно! Остается вопрос, можно ли делать такие вещи через вызовы SDK. На мой взгляд это ограничение - не более чем недосмотр разработчиков. Время покажет! Вложения ![]() Источник: http://axforum.info/forums/blog.php?b=421
__________________
Расскажите о новых и интересных блогах по Microsoft Dynamics, напишите личное сообщение администратору. |
|
|
|