среда, 13 мая 2015 г.

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

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

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

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




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, например вот так

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

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

Для того, чтобы в списке задач была сортировка по группам, к задаче надо добавлять группу. Это делается при добавлении задачи указанием поля 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);


Добавляем немного кода с обработками ошибок и - готово!

Комментариев нет:

Отправить комментарий