Битрикс КП. Импорт задач из XLSX файла


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

Итак, есть xlsx файл со списком задач. Из него можно узнать
  • TITLE
  • DESCRIPTION
  • RESPONSIBLE_ID
  • CREATED_BY
  • START_DATE_PLAN
  • END_DATE_PLAN
а также можно вычислить GROUP_ID и несколько свойств, которые были добавлены к задачам.

Сегодня:
- загружаем файл без перезагрузки страницы
- обрабатываем xlsx файл с помощью сторонней библиотеки
- добавляем свои свойства к задачам
- добавляем задачи в базу КП по конкретным группам

88db9767185e2d37642cc52db8053575.jpeg

FormData
Я уже где-то упоминала что не помню как работать с обычными формами, поэтому всё делаю на аджаксе. У меня так быстрее получается. Самой большой проблемой тут виделось скачивание файла и отправка его серверу без перезагрузки страницы. Недолгое гугление выдало мне FormData, что и было использовано.
Да, это не поддерживается "неновыми" браузерами, но у меня не стояло задачи написать универсальный инструмент для всех.
Итак, пишем обработчик клика по кнопочке, который и будет запускать всё действо.

$(document).ready(function()
{
 $('#btn_send_form').click(function(event)
 {
  //b_PS - это айдишка поля для показа статуса
  $("#b_PS").empty().append('<img src="loading.gif">'); //это "чтобы крутилось" пока скрипт выполняется
 
  var fd = new FormData();  //то что нам надо!
  //PS - это айдишка инпута типа файл, от которого и берём инфу
  fd.append('file', $('#PS')[0].files[0]); //добавляем туда нужные поля - файл
  fd.append('action', 'import_tasks'); //и поле для указания аджакс скрипту что делать то )
 
  $.ajax({
   url : 'ajax_import.php',
   type: 'POST',
   data : fd,
   processData: false, //вот это облизательно!
   contentType: false,
   success:function(data, textStatus, jqXHR){
    $("#b_PS").empty().append(data); //чистим крутилку и добавляем ответ от обработчика
   }
  });
 
  event.preventDefault();  //на всякий случай
 
 });
});
//ну и добавляем строчечку для неандертальцев
if(!window.FormData)
{
 document.write("<span style="color:red">Ваш браузер не поддерживается этим скриптом</span>");
  
XLSXReader
Эта замечательная библиотечка позволяет нам считывать содержимое xlsx файла. Даже со всех содержащихся там листов. Так как всяких извращений типа графиков и формул задачи не содержат, то спокойно используем этого клопа для нашей работы.
Для дальнейшего использования была накарябана функция, которая на вход получает путь к файлу и возвращает нам массив с построчными данными, содержащимися в импортируемом файле. Так как первая строка содержит названия столбцов, то было решено привести массив в ассоциативный вид, где индексами будут названия столбцов, а значениями - соответственно построчное содержимое.

Замечание: даты в xlsx содержатся в каком-то своём формате, соответственно надо их переработать в человеческий вид. Библиотека XLSXReader предоставляет для этого метод, который и используется.
* string $filename - полный путь к файлу
* array $date_indexes - массив с индексами столбцов, где содержится дата (см. код)
function read_xlsx($filename, $date_indexes = array())
{
 //начинаем обработку икселя
 $xlsx = new XLSXReader($filename);
 //имена листов (мы юзаем например первый)
 $sheetNames = $xlsx->getSheetNames();
 //полная инфа с листа
 $sheetData = $xlsx->getSheetData($sheetNames[1]);
 
 //перерабатываем инфу в нужный вид
 $arData = array();
 $first_row = array();
 foreach($sheetData as $key=>$row)
 {
  //запоминаем первую строку и будем использовать её как индексы
  if (!count($first_row))
  {
   $first_row = $row;
   continue;
  }
 
  //формируем нужную строку-массив
  $arrow = array();
  foreach($row as $rowkey=>$value)
  {
   $index = $first_row[$rowkey];
   //если заданы индексы для дат, то преобразовываем их из формата 
   //    экселя в формат человеческой даты
   if (in_array($rowkey, $date_indexes) && is_numeric($value))
    $value = date('d.m.Y', XLSXReader::toUnixTimeStamp($value));
 
   $arrow[$index] = $value;
  }
  $arData[$key] = $arrow;
 }
 
 return $arData;
}
 
Собственно, в скрипте обработчике фукнция вызывается вот так:
$file_array = read_xlsx($_FILES['file']['tmp_name']);
 
Пользовательские свойства задач
Идём Настройки -- Настройки продукта -- Пользовательские поля
Добавляем новое свойство. Для того, чтобы оно принадлежало задаче надо задать поле Объект в TASKS_TASK, например вот так
430ca190e7c1bc6a80ef1ffb75affd4c.jpg

Таким образом это поле будет принадлежать задаче и спрашиваться при её добавлении и, если заполнено, то отображаться при просмотре.
889940f9ebd7191027a9dff79950308c.jpg

Группа задачи

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

Для этого сначала считываем все группы, которые существуют в портале. А затем по имени находим айдишку. Собственно всё =)
 //собираем группы
if (!CModule::IncludeModule("socialnetwork"))
 die('<b style="color:red">module socialnetwork problem</b>');
 
$arGroups = array();
$hGroups = CSocNetGroup::GetList(
 array("ID" => "DESC"),
 array('ACTIVE'=>'Y'),
 false,
 false,
 array('ID', 'NAME')
);
while($row = $hGroups->Fetch())
 $arGroups[$row['NAME']] = $row['ID'];
Добавление задачи
Использую старый класс CTasks, ибо новый у меня так и не взлетел. Может, у меня руки кривые, а может я слишком ленивая чтобы разбираться.
Собираем поля, нужные для создания задачи:
  • RESPONSIBLE_ID - айдишка ответственного
  • CREATED_BY - айдишка постановщика задачи
  • UF_TASK_TP_ADRES - наше пользовательское поле. у нас тут адрес.
  • GROUP_ID - айдишка соц.группы
  • TITLE - название задачи
  • DESCRIPTION - описание задачи
  • START_DATE_PLAN - дата начала
  • END_DATE_PLAN - дата окончания
 if (!CModule::IncludeModule("tasks"))
 die('<b style="color:red">module tasks problem</b>');
$ctio = new CTasks;
//создаём задачу
$task_ID = $ctio->Add($arTaskFields);
Добавляем немного кода с обработками ошибок и - готово!


Просмотров: 3511