КП: Универсальная форма подачи заявки

КП: Универсальная форма подачи заявки

1021
21.06.2015

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

Поступила мне тут недавно интересная задача - необходимо было реализовать бизнес-процесс, на базе коробочной версии 1С-Битрикс, который позволит сотрудникам на портале подавать различные заявки. Самое главное в данном процессе то, что список всемозможных услуг может расширяться администратором портала до бесконечности.

У процесса, при этом, есть общие детали - есть обязательные для заполнения во всех видах услуг поля, а есть поля, которые уникальны для одной конкретной услуги.

Вкратце алгоритм. Пользователь заходит в раздел подачи заявок. Выбирает из предложенного списка нужную услугу. Вводит какой-то сопроводительный текст в текстовое поле; заполняет все обязательные для заполнения поля и нужные из необязательных. Отправляет заявку ответственному. 

Дальше система отправляет уведомление ответственному о том, что у него появилась новая заявка (вообще все изменения статусов заявки должны сопровождаться соответствующими уведомлениями всем, кто должен принять участие в данный момент по данной заявке). Автору заявки уходит уведомление о том, что для заявки назначен ответственный (выбирается автоматически из описания услуг).

Ответственный просматривает заявку. При необходимости - может делегировать заявку другому ответственному (об этом уведомление уходит и новому ответственному и автору заявки).

Если заявка приемлема и для заявки не требуется согласование (также устанавливается в настройках услуг) - выполняет заявку и завершает ее нажатием на соответствующую кнопку.

Если заявка не приемлема - отклоняет заявку

Если заявка требует согласования, то вместо кнопки "Закрыть заявку" (которая положительно завершает заявку) ответственному доступна кнопка "Отправить на согласование", после чего запускается простой процесс согласования всеми, указанными для услуги лицами.

Вот такой вот вкратце алгоритм. Он, естественно, может быть на много шире с более тонким ветвлением условий (по данной задаче он и был немного шире, но тут опишу суть, может кому пригодится ...).

Реализация

Для реализации создаем 2 инфоблока: "Заявки пользователей" - для хранения всех заявок от пользователей и "Услуги" - для описания всех услуг.

Инфоблок с услугами имеет свойства:

Анонсовое значение инфоблока с заявками будем использовать для записи описательного сопроводительного текста к заявке, а детальное описание - для комментариев по заявке (Если комментарии нужны древовидные с возможностью ведения комментариев к комментариям - придется создавать еще один инфоблок. В моем случае было достаточно и одного доступного поля). Для данного инфоблока создаем набор свойств:

Далее - создаем в файловой структуре портала соответствующих раздел. Компонентом "news.list" выводим список всех заявок с разными видами фильтрации - по полю "Ответственный" для отбора заявок, где текущий пользователь - установлен в качестве ответственного, по полю "Инициатор" - для отбора заявок, где пользователь установлен в качестве автора. Тут ничего сложного - банальный вывод элементов инфоблока с фильтрацией.

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

Для выбора списка услуг взял компонент news.list и просто допилил его шаблон. При выборе нужной услуги с помощью JS формируется набор полей, которые должны быть дополнительно заполнены для выбранной услуги. Для поля "Файлы" использовал типовой компонент "main.file.input" с предустановленным шаблоном "drag_n_drop". Суть данного компонента в том, что при его использовании файлы автоматически отправляются на сервер и в форму помещаются ID уже сохраненных файлов. Т.е. нет необходимости в обработке на стороне сервера еще и файлов.

Итак, пользователь выбрал услугу, ввел все необходимые данные, загрузил все файлы и нажал на кнопку "Подать заявку". Отправка реализована средствами JS: скрипт проверяет, заполнены ли все обязательные для заполнения поля и, если да, - отправляет пост-запросом по аяксу данные в специальный скрипт.

У данного скрипта на сервере есть 3 основные функции:

Остановлюсь подробнее на каждой из них. Начну с самой простой:

     function NotifyUser($UID,$text,$EID){
         if (IsModuleInstalled("im") && CModule::IncludeModule("im"))
         {
             $arMessageFields = array(
                 "TO_USER_ID" => $UID,
                 "FROM_USER_ID" => 1,
                 "NOTIFY_TYPE" => IM_NOTIFY_SYSTEM,
                 "NOTIFY_MODULE" => "iblock",
                 "NOTIFY_TAG" => "BLOG|POST|".$EID,
                 "NOTIFY_MESSAGE" => $text,
                 "NOTIFY_MESSAGE_OUT" => $text
             );
             CIMNotify::Add($arMessageFields);
         }
     } 

Данная функция просто отправляет текст $text пользователю с ID $UID.

Далее - функция добавления комментария.

     function addCommentToRequest($item_id, $comment, $UID){
         $arItem = CIBlockElement::GetByID($item_id)->Fetch();
     
         $presentComment = $arItem['DETAIL_TEXT'];
         $commenterName = CUser::GetFullName($UID);
         global $DB;
         $addComment = '<p class="commenter"><b>'.$commenterName.'</b> '.date($DB->DateFormatToPHP(CLang::GetDateFormat("FULL"))).'</p>';
         $addComment .= '<div>'.$comment.'</div>';
     
         $el = new CIBlockElement;
         $arLoadProductArray = Array(
             "MODIFIED_BY"    => $GLOBALS['USER']->GetID(),
             "DETAIL_TEXT"   => $presentComment. $addComment,
             "DETAIL_TEXT_TYPE"   => "html",
         );
         $el->Update($item_id, $arLoadProductArray);
         return $presentComment.$addComment;
     }

Данная функция считывает уже добавленные ранее комментарии по заявке, добавляет к ним новый комментарий и все это записывает в хтмл-формате. Функция возвращает суммарное значение комментариев для замены в отображении заявки.

И последняя, самая важная функция - функция сохранения изменений по заявке.

     function  SaveRequest($DATA,$ID=false){
         $el = new CIBlockElement;
     
         if(is_array($DATA['APPEND_FIELDS'])){
             $append = '<h4>Дополнительные поля</h4> <ul>';
             foreach ($DATA['APPEND_FIELDS'] as $key=>$appnd) {
                 $append .= '<li><b>'.$key.'</b>: '.$appnd.'</li>';
             }
             $append .= '</ul>';
             $DATA['REQTEXT'].= $append;
         }
         $PROP = array(
             'SERVICE'=>$DATA['SERVICE'],
             'STATUS'=>304,
             'PRIORITY'=>308,
             'OWNER'=>$GLOBALS['USER']->GetID(),
             'RESPONSIBLE'=>$DATA['RESPONSIBLE'],
             'TERM'=>$DATA['TIMER_END'],
             'MATCHING_LIST'=>$DATA['MATCHING_LIST']
         );
     
         if(!empty($DATA['FILES'])){
             $PROP['FILES'] = $DATA['FILES'];
         }
     
         $arLoadProductArray = Array(
             "MODIFIED_BY"    => $GLOBALS['USER']->GetID(),
             "IBLOCK_SECTION_ID" => false,
             "IBLOCK_ID"      => IBLOCK_REQUESTS,
             "PROPERTY_VALUES"=> $PROP,
             "NAME"           => $DATA['SERVICENAME'],
             "ACTIVE"         => "Y",
             "PREVIEW_TEXT"   => $DATA['REQTEXT'],
             "PREVIEW_TEXT_TYPE"   => "html",
         );
     
         if($PRODUCT_ID = $el->Add($arLoadProductArray))
             return array('success'=> $PRODUCT_ID);
         else
             return array('error'=>"Error: ".$el->LAST_ERROR);
     } 

Все дополнительные поля дописываем к опистельному тексту заявки. Статус заявки устанавливаем в состояние "Новая" (id статуса = 304), приоритет - "Нормальный" (id значения приоритета 308). Функция возвращет ID новой созданной заявки.

И напоследок - бизнес-процесс, который запускается при отправке на согласование (точнее данный бизнес-процесс запускается каждый раз при изменении заявки).

Бизнес-процесс согласования заявки

Самое главное - первый блок с запросом данных из инфоблока:

     if (\Bitrix\Main\Loader::includeModule('iblock')) { 
             function ParseDateFromString($datetime){ 
                 $format = "DD.MM.YYYY HH:MI:SS"; 
                 if ($arr = ParseDateTime($datetime, $format)) { 
                     return $arr; 
                 } else { 
                     return false; 
                 } 
             } 
         
             $ID = {=Document:ID}; 
             $IblockD = {=Document:IBLOCK_ID}; 
             $db_props = CIBlockElement::GetProperty($IblockD, $ID, array("sort" =&gt; "asc"), Array("CODE"=&gt;"RESPONSIBLE")); 
             $RESPONSIBLE = false; 
             if($ar_props = $db_props-&gt;Fetch()) 
                 $RESPONSIBLE = IntVal($ar_props["VALUE"]); 
             if($RESPONSIBLE &amp;&amp; intval($RESPONSIBLE)&gt;0){ 
                 $this-&gt;SetVariable('Responsible', $RESPONSIBLE); 
         
             $db_props = CIBlockElement::GetProperty($IblockD, $ID, array("sort" =&gt; "asc"), Array("CODE"=&gt;"TERM")); 
             $TERM = false; 
             if($ar_props = $db_props-&gt;Fetch()){ 
                 $TERM = ParseDateFromString($ar_props["VALUE"]); 
                 $Seconds = mktime($TERM['HH'],$TERM['MI'],$TERM['SS'],$TERM['MM'],$TERM['DD'],$TERM['YYYY']) - time(); 
                 $this-&gt;SetVariable('Term', $Seconds); 
                 $db_props = CIBlockElement::GetProperty($IblockD, $ID, array("sort" =&gt; "asc"), Array("CODE"=&gt;"FILES")); 
                 $FILES = array(); 
                 while($ar_props = $db_props-&gt;Fetch()){ 
                     $img = CFile::GetPath($ar_props['VALUE']); 
                     $link = '[url=http://sitename.ru'.$img.']link[/url]'; 
                     $FILES[] = $link; 
                 } 
                 $FILES = implode(' ',$FILES); 
                 if(!empty($FILES)) 
                     $this-&gt;SetVariable('attach', 'Вложения по заявке: ' . $FILES); } 
             } 
         }

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

P.S. во вложении - результаты работ. pai-bx-requests.tar.gz - модификация компонента "news" со всей логикой работы (Помещать в папку /bitrix/components/). requests_from_user.tar.gz - подключение механизма в публичной части.



Благодарю за внимание! Делитесь вашими замечаниями в комментариях ниже.


P.S. Обращайтесь ко мне за приобретением лицензий и продлений на 1C-Битрикс "Управление сайтом", лицензий на облачную и коробочную версии Битрикс 24 а также за приобретением и внедрением готовых решений на базе 1С-Битрикс от партнеров. За более подробной информацией свяжитесь со мной любым удобным для вас способом


Комментарии

Еще никто не комментировал данную публикацию. Будьте первыми!

Добавить комментарий

captcha

Возврат к списку