Кастомизация
13
Июл
26

Фильтрация полей Lookup в CRM 4

Псевдофильтр

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

  • Предположим, что у нас есть два объекта – Регион и Город – Регион является родительским по отношению к Город, т.е. в объекте Город есть лукап на объект Регион. Откройте в объекте Город представление «Город представление поиска» и добавьте еще один столбец поиска: «Регион»;




  • Теперь вынесем оба эти объекта (Регион и Город) в виде лукапов на форму какого-либо третьего объекта (например Бизнес-партнера). На onload формы третьего объекта вешаем следующий скрипт:
    document.FilterLookup = function(source, target) {
    	if (IsNull(source) || IsNull(target)) { return; }
    	var name = IsNull(source.DataValue) ? '' : source.DataValue[0].name;
    	name=escape(name);
    	target.additionalparams = 'search=' + name;
    }
    
  • А на событие onchange лукапа Регион добавьте следующий код (т.к. этот код передает в скрипт на онлоаде два параметра – что фильруем и где фильтруем – то аналогичным способом можете повесть фильтр и на другие лукапы на данной форме):
    document.FilterLookup(crmForm.all.new_stateid, crmForm.all.new_cityid);
    


  • Когда пользователь выберет Регион, а затем попытается выбрать Город, то поле поиска у него уже будет заполнено значением поля Регион И соответственно все записи в представлении будут отобраны по указанному региону. Только учтите, что поиск осуществляется по двум полям (в этом примере – в Вашем может быть и больше) – Имя и Регион – таким образом если поле Имя совпадет с введенной строкой поиска, то эта строчка также будет отображена, вне зависимости от значения столбца Регион.


Жесткий фильтр

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

  • Сначала подправим исходный файл CRM. Следующий код должен быть помещен где-нибудь в файле <папка сайта CRM>\_controls\lookup\lookupsingle.aspx:
    <script runat="server"> 
    protected override void OnLoad( EventArgs e ) 
    { 
        base.OnLoad(e); 
        crmGrid.PreRender += new EventHandler( crmgrid_PreRender ); 
    } 
    void crmgrid_PreRender( object sender , EventArgs e ) 
    {
        //Поскольку мы не хотим испортить другие лукапы, проверяем, что параметр search начинается с <fetch
    
        if (crmGrid.Parameters["search"] != null && crmGrid.Parameters["search"].StartsWith("<fetch")) { 
            crmGrid.Parameters.Add("fetchxml", crmGrid.Parameters["search"]);  
            crmGrid.Parameters.Remove("searchvalue");  
            //Чтобы юзверы не смогли создать новую запись из лукапа и выбрать ее – скрываем кнопку создания новой записи
            this._showNewButton = false; 
        } 
    } 
    </script>
    


  • Далее мы должны передать в лукап (который мы немного подправили 🙂 ) fetchxml строку для отбора нужных записей – соответственно сначала Вы должны ее составить (в этом примере на объекте Контакт отбираются Родительcкие клиенты, которые являются только Бизнес-партнерами и имеют название Газпром). Подробнее об fetchxml читайте в статье FetchXML, а о том как автоматизировать их создание смотрите инструмент FetchXML Builder. Поместите следующий код на онлоад того объекта, лукапы которого хотите фильтровать (измените только fetchxml строку и имя поля лукап):
    var field = crmForm.all.parentcustomerid; 
    
    //Отключаем поле поиска в диалоговом окне лукапа
    field.lookupbrowse = 1; 
    
    //Передаем fetch xml через параметр поиска лукапа
    field.AddParam("search", 
    "<fetch mapping='logical'><entity name='account'>" 
    + "<filter><condition attribute='name' operator='eq' value='Газпром' /></filter></entity></fetch>");
    
  • При использовании этого способы Вы должны учитывать одну вещь – он никак не влияет на автоматическое заполнение и на помощника форм. Поэтому, чтобы исключить возможность обхода Вашего фильтра Вы должны отключить эти компоненты.



Комментарии (26)
  • Костя 13.07.2009

    По первому варианту лучше добавить escape(name);
    Чтобы не было проблем с кодировкой русских букв. Я у себя описывал
    http://ms-dynamics-crm.com.ua/2009/02/16/filter-in-microsoft-dynamics-crm-40/

  • slivka_83 13.07.2009

    Пятая строчка сверху 🙂
    name=escape(name);

  • Костя 13.07.2009

    Сорри за невнимательность 🙂

  • slivka_83 13.07.2009

    Я сначала тоже взял код без escape 🙂 но вместо кирилицы были квадратики 🙂 пришлось штудировать мануалы по яваскрипту 🙂

  • Андрей Мурзин 13.07.2009

    Хочу заметить, что данный код не работает, если в названии обоих полей присутствует id, к примеру: customerid и responsiblecontactid. Код приводит к ошибке на странице.

  • slivka_83 13.07.2009

    Наверно тут дело не в id 🙂 а в том, что Вы пытаетесь фильтровать мульти-лукапы 🙂 а в данном случаи мы редактировали только lookupsingle.aspx, который отвечает за единичные лукапы 🙂

  • Дмитрий 13.07.2009

    а как сделать чтобы и в помощнике по созданию форм работало?

  • slivka_83 13.07.2009

    Пока встречать такой реализации не приходилось!

  • Samson 13.07.2009

    М возвращаясь к августу. Как побороть ошибку при фильтрации лукапов?

  • slivka_83 13.07.2009

    Боюсь, что вопрос не ясен? о какой ошибке идет речь?

  • Alex 13.07.2009

    Речь об ошибке, о которой написал Андрей Мурзин 18.08.2009.
    У меня тоже была такая ошибка, помогло перенести функцию из document в window.
    На onload формы пишем
    window.FilterLookup = function(source, target)
    {
    ……..
    }
    и на onchange исправляем
    FilterLookup(…,…)
    У меня это решило проблему.

  • Александр 13.07.2009

    Добрый день!

    Подскажите можно ли использовать 1 часть поста — Псевдофильтр и передавать ему несколько параметров, к примеру:
    нужно получить города не 1 области, а 2 или 3, и как тогда передавать значения для фильтрации?

  • slivka_83 13.07.2009

    Добрый день. Не думаю что такое возможно. Тут нужно использовать 2-ой способ.

  • Алексей 13.07.2009

    Здравствуйте.
    Сделали по вышеописанному методу фильтр на лукап возможных сделок. Все работает отлично. Но тут появилась обратная задача. По умолчанию поиск сделок отображает только открытые сделки. Шаманство с фильтрами на statuscode и statecode по аналогии с обычными фильтрами ни к чему не привело. Есть ли какая-нибудь возможность при лукапе отображать и завершенные сделки?

  • slivka_83 13.07.2009

    Добрый день 🙂

    http://mmcrm.ru/?p=1071
    http://mmcrm.ru/?p=624

  • Алексей 13.07.2009

    Спасибо!

  • Dmitry 13.07.2009

    Добрый день!

    столкнулся со следующей проблемой и буду примного признателен за любую помощь.

    при открытии некоторых контрактов возникает ошибка:
    Microsoft CRM Error Report:
    Error Description:
    An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

    Error Details:
    Exception of type ‘System.Web.HttpUnhandledException’ was thrown.

    Full Stack:
    [ArgumentException: This lookup can only display one item. Lookup ID = customer]
    at Microsoft.Crm.Application.Components.Sdk.FormControls.Web.PartyListControl.set_Value(Object value)
    at Microsoft.Crm.Application.Components.Sdk.FormControls.Web.CrmWebFormDataControlUIWrapper.SetValue()
    at Microsoft.Crm.Application.Forms.EndUserForm.BindDataRecursively(Control control)
    at Microsoft.Crm.Application.Forms.EndUserForm.BindDataRecursively(Control control)
    at Microsoft.Crm.Application.Forms.EndUserForm.BindDataRecursively(Control control)
    at Microsoft.Crm.Application.Forms.EndUserForm.BindDataRecursively(Control control)
    at Microsoft.Crm.Application.Forms.EndUserForm.BindDataRecursively(Control control)
    at Microsoft.Crm.Application.Forms.EndUserForm.BindDataRecursively(Control control)
    at Microsoft.Crm.Application.Forms.CustomizableForm.Execute(Entity entity, String formType)
    at Microsoft.Crm.Web.MA.CampaignResponseDetailPage.ConfigureForm()
    at Microsoft.Crm.Application.Controls.AppUIPage.OnPreRender(EventArgs e)
    at System.Web.UI.Control.PreRenderRecursiveInternal()
    at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

    [HttpUnhandledException: Exception of type ‘System.Web.HttpUnhandledException’ was thrown.]
    at System.Web.UI.Page.HandleError(Exception e)
    at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
    at System.Web.UI.Page.ProcessRequest(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
    at System.Web.UI.Page.ProcessRequest()
    at System.Web.UI.Page.ProcessRequest(HttpContext context)
    at ASP.finam_ma_campaignresponse_edit_aspx.ProcessRequest(HttpContext context)
    at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
    at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

    Other Message:

    Error Number:

    Source File:
    Not available

    Line Number:
    Not available

    Date: 10-10-2011

    Time: 20:22:27

    Server: crm

    Request URL:
    http://crm:5555/FINAM/ma/campaignresponse/edit.aspx?id={ACB0418F-32F0-E011-8C0E-001A6433B300}&_CreateFromType=4&_CreateFromId={1CE5A959-49A7-4561-9A20-C19D7FCEF541}

    судя по описанию, в поле lookup — customer сохранено более одного значения. в связи с чем это может происходить (не часто но периодически) и как это можно вылечить (возможно руками в бд)

    Большое спасибо

  • slivka_83 13.07.2009

    Добрый день!
    Боюсь что раньше с такой не сталкивался. Есть подобная только для CRM 3.0: http://kbalertz.com/914799/Error-message-appointment-Microsoft-Dynamics-lookup-display-Lookup.aspx

  • Азат 13.07.2009

    Вопрос по жесткому фильтру
    Как сделать, чтобы в лукапе открывались только объекты, в которых ownerid = текущий пользователь?
    (в ролях безопасности доступ на чтение, запись и т.п. к данному объекту открыт для всех пользователей)

  • slivka_83 13.07.2009

    Вам нужно сформировать фетч в котором отфильтровать записи по теущему пользователю. ID текущего пользователя можете вернуть с помощью WhoAmI (http://msdn.microsoft.com/en-us/library/bb890244.aspx).

  • Азат 13.07.2009

    Кстати, а какой запрос отправляется из веб-интерфейса на CRM-сервер, когда в расширенном поиске или представлении объекта настроен фильтр «владелец (ownerid) = текущий пользователь»?

  • slivka_83 13.07.2009

    кстати да 🙂 у Вас есть CRM 2011& сформируйте такой запрос в Расширенном поиске и посмотрите его фетч (для этого в Расширенном поиске предусмотрена специальная кнопка) 🙂

  • Азат 13.07.2009

    в том-то и беда, что 2011-го нет, надо реализовать все это на 4.0. Как вытащить передаваемый фетч-запрос в четверке?

  • Александр 13.07.2009

    Азат, для жесткого фильтра используйте фильтрацию с помощью плагина (http://mmcrm.ru/?p=1230)
    Вытащить fetch можно следующим способом:
    1. Открыть расширенный поиск.
    2. Нажать комбинацию Ctrl+N.
    3. Формируете условие.
    4. Нажимаете «Найти», чтобы увидеть что вернул запрос. В адресную строку вставляете вот это:
    javascript:alert(resultRender.FetchXml.value);
    В сообщении будет fetch запрос.

  • Макс 13.07.2009

    ХЕЛП!((

    Решение «Псевдофильтр» в моей ситуации идеально! Но но всей видимости после какого то ролапа не поддерживается, Есть ли подобная альтернатива??

  • Макс 13.07.2009

    Ложная тревога) Был невнимателен, всё работает !! 🙂

*

code