Jump to content
SpravkaCRM.ru - Ваш справочник по CRM
Sign in to follow this  
SpravkaCRM.ru

Добавление фильтра в списке по записям из другого модуля

Recommended Posts

Всем привет!

Хочу поделиться методом, который позволяет добавлять фильтры в список записей модуля, когда надо найти все записи, у которых есть связи с определенной записью из другого модуля.

Сразу оговорюсь, что SuiteCRM позволяет выполнять подобный поиск стандартным способом, когда ищем в связке один-ко-многим. Например, должны найти все Контакты, принадлежащие определенному Контрагенту. Подобные связи можно видеть в настройках шаблона поиска в студии, и настраиваются они без вмешательства программиста путем работы с интерфейсом.

Мы же с вами поговорим о ситуациях, когда надо найти все записи модуля, который связан с другим модулем произвольным образом (возможно связью многие-ко-многим, а возможно вообще какими то сложными логическими схемами, главное чтобы эту связь можно было уместить в одном SQL-запросе).

Чтобы было понятней давайте рассмотрим пример:

Допустим, нам надо в модуль "Документы" в списке записей добавить фильтр, в котором мы сможем найти все документы, у которых за контрагента отвечает определенный пользователь.

Таким образом:

  1. Мы находимся в модуле Документы
  2. Нам надо отфильтровать Документы по пользователю (модуль Users)
  3. У каждого Документа есть связь с Контрагентами многие-ко-многим (в карточке Документа сабпанель Контрагенты)
  4. В Контрагенте есть связь с Пользователем через поле assigned_user_id
  5. Нам надо получить список Документов по фильтру

Стандартным способом без программирования мы сможем реализовать подобную задачу только используя модуль "Отчёты". Да. Так тоже можно.  Но не удобно. Хочется находиться в модуле Документы, а не "шарится" по другим модулям/отчётам.

Далее я тезисно опишу что нам понадобиться сделать, а потом покажу, как это будет выглядеть в файлах. Итак:

  1. Хотя механизм формирования фильтров и позволяет в них добавлять разную самописную отсебятину, но наиболее удобным средством, по результатам многочисленных опытов, стало добавление фильтра в виде поля модуля. То есть мы добавляем поле в модуль Documents, которое будет собой представлять как бы ссылку на модуль Users. А чтобы это поле не вносило изменения в структуру таблицы с документами, ему (этому полю) необходимо указать характеристику 'source' => 'non-db'.
  2. После выполнения быстрого восстановления с вновь добавленным полем модуля можно работать как с обычным полем: заходим в студию, и в модуле Документы помещаем его в макет поиска туда, куда удобно (имеет смысл работать только с макетом поиска, в других макетах это поле не будет работать, потому что не хранит данные в базе).
  3. В настройках поиска вручную задаем SQL-запрос, который должен будет выполниться, если мы введем какое то значение в фильтре в нашем поле.

Ну а теперь по конкретике:

  1. Создаем файл с описанием добавляемого поля: custom/Extension/modules/Documents/Ext/Vardefs/account_assigned_user.php: 
    <?php
    $dictionary['Document']['fields']['account_assigned_user'] = array (
        'required' => false,
        'source' => 'non-db',
        'name' => 'account_assigned_user',
        'vname' => 'LBL_ACCOUNT_ASSIGNED_USER',
        'type' => 'relate',
        'massupdate' => 0,
        'no_default' => false,
        'comments' => '',
        'help' => '',
        'importable' => 'true',
        'duplicate_merge' => 'disabled',
        'duplicate_merge_dom_value' => '0',
        'audited' => false,
        'inline_edit' => true,
        'reportable' => true,
        'unified_search' => false,
        'merge_filter' => 'disabled',
        'len' => '255',
        'size' => '20',
        'id_name' => 'id',
        'ext2' => 'Users',
        'module' => 'Users',
        'rname' => 'name',
        'quicksearch' => 'enabled',
        'studio' => 'visible',
    );

    Хотел бы обратить ваше внимание на следующу строку: 

    'id_name' => 'id',

    Вообще подобное поле положено создавать в паре с полем, которое будет хранить непосредственно id связанной записи в базе данных. Это когда мы хотим добавить связь один-ко-многим. И в параметре 'id_name' нужно было бы указать название подобного поля. Но в нашем случае в таблице с документами нам не надо ничего хранить. Все необходимые данные мы будем получать из других таблиц. По этому в параметре 'id_name' мы указываем значение 'id' (если не вдаваться сильно в детали, то неуказать ничего мы тоже не можем, потому что этот параметр потом будет учавствовать в SQL-запросе в виде `documents`.`<id_name>`, и если ничего не указать, то будет SQL-ошибка).

  2. Создаем файл с локализацией создаваемого поля: custom/Extension/modules/Documents/Ext/Language/ru_RU.account_assigned_user.php 
    <?php
    
    $mod_strings['LBL_ACCOUNT_ASSIGNED_USER'] = 'Ответственный за Контрагента';

     

  3. Выполняем быстрое восстановление. После этого можно идти в Студию и настраивать внешний вид поиска: 2018-03-28_15-00-17.thumb.png.ecebe4b854894c4b0fc1a7baed4b3d9b.png
  4. Переходим в модуль "Документы, и видим, что поле появилось в списке фильтров (верстка кривая, но сейчас не о этом): 2018-03-28_15-01-33.thumb.png.13b24056faf3ff7f2eb4cfa2d69ca6b9.png
  5. Нам необходимо немного модернизировать отображение этого поля. Дело в том, что если мы выбор пользователя оставим в текущем виде, то в наш SQL-запрос будет попадать имя пользователя. А это немного не то, что надо. Нам надо, чтобы в SQL-запрос попадал ID выбранного поля. Для этого мы поле переделываем в выпадающий список: открываем файл custom/modules/Documents/metadata/searchdefs.php, находим в нем секцию account_assigned_user, и меняем ее на 
          'account_assigned_user' => 
          array (
            'type' => 'enum',
            'studio' => 'visible',
            'label' => 'LBL_ACCOUNT_ASSIGNED_USER',
            'id' => 'ID',
            'link' => true,
            'width' => '10%',
            'default' => true,
            'name' => 'account_assigned_user',
              'function' =>
                  array (
                      'name' => 'get_user_array',
                      'params' =>
                          array (
                              0 => false,
                          ),
                  ),
          ),

    После данной манипуляции фильтр по пользователю должен выглядеть как список пользователей (там опять кривая верстка, но мы опять не про нее): 2018-03-28_15-20-11.thumb.png.cc9f2c5781492ed5e17c1304de737534.png

  6. Если сейчас выбрать в этом поле пользователя, и нажать кнопку "Найти" в поиске, то мы ничего не получим, потому что еще не настроили механизм поиска нужных нам записей. А для этого переходим к файлу custom/modules/Documents/metadata/SearchFields.php (он как раз должен был создастся после манипуляций в студии), и вставляем в него блок такого содержания: 
        'account_assigned_user' =>
            array (
                'query_type' => 'format',
                'operator' => 'subquery',
                'subquery' => '
                              SELECT
                                `documents`.`id`
                              FROM
                                `documents`
                              INNER JOIN 
                                `documents_accounts`
                                ON `documents_accounts`.`document_id` = `documents`.`id`
                                AND `documents_accounts`.`deleted` = 0
                              INNER JOIN
                                `accounts`
                                ON `accounts`.`id` = `documents_accounts`.`account_id`
                                AND `accounts`.`deleted` = 0
                              WHERE
                                `documents`.`deleted` = 0
                                AND `accounts`.`assigned_user_id` = "{0}"
              ',
                'db_field' =>
                    array (
                        0 => 'documents.id',
                    ),
            ),

    Как видно (надеюсь), данный код ищет все id в таблице documents, которые связаны с контрагентом, у которого в assigned_user_id указано выбранное нами значение.

  7. А вот такой SQL-запрос соберется в итоге при попытке воспользоваться данным фильтром (указаю юзера с айди = 1 - админ): 

    SELECT  documents.id , documents.assigned_user_id , documents.id , documents.document_name , documents.document_revision_id , documents.doc_id , documents.doc_type , documents.doc_url , documents.category_id , documents.subcategory_id , documents.exp_date  , jt0.user_name assigned_user_name , jt0.created_by assigned_user_name_owner  , 'Users' assigned_user_name_mod, documents.date_entered , LTRIM(RTRIM(CONCAT(IFNULL(jt1.first_name,''),' ',IFNULL(jt1.last_name,'')))) account_assigned_user , documents.created_by  FROM documents   LEFT JOIN  users jt0 ON documents.assigned_user_id=jt0.id AND jt0.deleted=0
    
     AND jt0.deleted=0 LEFT JOIN users jt1 ON documents.id = jt1.id AND jt1.deleted=0  where ((documents.id IN (
                              SELECT
                                `documents`.`id`
                              FROM
                                `documents`
                              INNER JOIN 
                                `documents_accounts`
                                ON `documents_accounts`.`document_id` = `documents`.`id`
                                AND `documents_accounts`.`deleted` = 0
                              INNER JOIN
                                `accounts`
                                ON `accounts`.`id` = `documents_accounts`.`account_id`
                                AND `accounts`.`deleted` = 0
                              WHERE
                                `documents`.`deleted` = 0
                                AND `accounts`.`assigned_user_id` = "1"
              ))) AND documents.deleted=0 ORDER BY documents.document_name ASC

     

  8. Подобным образом можно заложить любую логику поиска нужной записи. Пользуйтесь )))

 

 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

×
×
  • Create New...