Удобная консоль регламентных и фоновых заданий




Принцип обмена данными из 1С с сайтом (на MySQL) и выдачи (публикации) этих данных по запросу.
PHP-Скрипт автоматической загрузки данных из файла данных в формате CSV в базу данных сайта работающего на WordPress.

В продолжение моей темы: 1С:Альфа-Авто Автосалон Автосервис: обмен с сайтом.
С помощью данного скрипта можно загружать в автоматическом режиме, по расписанию, данные сервисных книжек (ремонтов авто) из 1С:Альфа-Авто Автосалон Автосервис.
Также можно загружать данные в ручном режиме: для этого делается скрытая страница, где размещается специальная кнопка.
Комментарии размещенные внутри скрипта разъяснят логику и порядок действия.
Комментарии с "/////    echo" использовались для отладки.
Дополнительно создана таблица для журналирования результатов загрузки данных.
Скрипт включает в себя защиту от SQL инъекций (думаю безопасность соблюдена в полной мере).
В кратце:
1. Пишется скрипт, который запускает этот.
2. Создается регламентное задание в WordPress, по которому запускается скрипт из п.1. 
3. Этот скрипт осуществляет проверку на существование файла обмена в папке.
4. Если данные не новые, загрузка не производится.
5. Если данные новые, очищается таблица сервисных книжек.
6. Загружаются новые данные.

Собственно сам скрипт:

<?php // Полная загрузка сервисных книжек, создан 2024-01-05 12:44:55

global $wpdb2;
global $failure;
global $file_hist;

/////  echo '<H2><b>Старт загрузки</b></H2><br>';

$failure=FALSE;
//подключаемся к базе
$wpdb2 = include_once 'connection.php'; ; // подключаемся к MySQL
// если не удалось подключиться, и нужно оборвать PHP с сообщением об этой ошибке
if (!empty($wpdb2->error))
{
/////   echo '<H2><b>Ошибка подключения к БД, завершение.</b></H2><br>';
$failure=TRUE;
wp_die( $wpdb2->error );
}

$m_size_file=0;
$m_mtime_file=0;
$m_comment='';
/////проверка существования файлов выгрузки из 1С
////файл выгрузки сервисных книжек
$file_hist = ABSPATH.'/_1c_alfa_exchange/AA_hist.csv';
if (!file_exists($file_hist))
{
/////   echo '<H2><b>Файл обмена с сервисными книжками не существует.</b></H2><br>';
$m_comment='Файл обмена с сервисными книжками не существует';
$failure=TRUE;
}

/////инициируем таблицу лога
/////если не существует файла то возврат и ничего не делаем
if ($failure){
///включает защиту от SQL инъекций и данные можно передавать как есть, например: $_GET['foo']
/////   echo '<H2><b>Попытка вставить запись в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>$m_comment));
wp_die();
/////    echo '<H2><b>Возврат в начало.</b></H2><br>';
return $failure;
}
/////проверка лога загрузки, что бы не загружать тоже самое
$masiv_data_file=stat($file_hist);   ////передаем в массив свойство файла
$m_size_file=$masiv_data_file[7];    ////получаем размер файла
$m_mtime_file=$masiv_data_file[9];   ////получаем дату модификации файла
////создаем запрос на получение последней удачной загрузки
////выбираем по штампу времени создания (редактирования) файла загрузки AA_hist.csv, $m_mtime_file

/////   echo '<H2><b>Размер файла: '.$m_size_file.'</b></H2><br>';
/////   echo '<H2><b>Штамп времени файла: '.$m_mtime_file.'</b></H2><br>';
/////   echo '<H2><b>Формирование запроса на выборку из лога</b></H2><br>';
////препарируем запрос
$text_zaprosa=$wpdb2->prepare("SELECT * FROM `vin_logs` WHERE `last_mtime_upload` = %s", $m_mtime_file);
$results=$wpdb2->get_results($text_zaprosa);

if ($results)
{   foreach ( $results as $r)
{
////если штамп времени и размер файла совпадают, возврат
if (($r->last_mtime_upload==$m_mtime_file) && ($r->last_size_upload==$m_size_file))
{////echo '<H2><b>Возврат в начало, т.к. найдена запись в логе.</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>'Загрузка отменена, новых данных нет, т.к. найдена запись в логе.'));
wp_die();
return $failure;
}
}
}
////если данные новые, пишем в лог запись о начале загрузки
/////echo '<H2><b>Попытка вставить запись о начале загрузки в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>0, 'last_size_upload'=>$m_size_file, 'comment'=>'Начало загрузки'));

////очищаем таблицу
$clear_tbl_zap=$wpdb2->prepare("TRUNCATE TABLE %s", 'vin_history');
$clear_tbl_zap_repl=str_replace("'","`",$clear_tbl_zap);
$results=$wpdb2->query($clear_tbl_zap_repl);
/////   echo '<H2><b>Очистка таблицы сервисных книжек</b></H2><br>';
if (empty($results))
{
/////   echo '<H2><b>Ошибка очистки таблицы книжек, завершение.</b></H2><br>';
//// если очистка не удалась, возврат
$failure=TRUE;
wp_die();
return $failure;
}

////загружаем данные
$table='vin_history';         // Имя таблицы для импорта
//$file_hist Имя CSV файла, откуда берется информация     // (путь от корня web-сервера)
$delim=';';          // Разделитель полей в CSV файле
$enclosed='"';      // Кавычки для содержимого полей
$escaped='\

15 Comments

  1. VmvLer

    кроме показа инфы из ЖР не увидел полезных отличий от типовой

    Reply
  2. Alxby

    (1)Обработка разрабатывалась в первую очередь как средство, независимое от сторонних библиотек. Основной функционал, конечно же, совпадает с типовой обработкой. Из отличий от типовой могу назвать: отображение в списке дополнительных данных заданий (например длительности или расписания), более высокую скорость работы, легкое получение информации об ошибках и сообщениях, удобный интерфейс. Мотивом к созданию этой обработки послужила неудовлетворенность скоростью работы типовой. А информация из ЖР здесь не используется.)

    Reply
  3. starik-2005

    Молодца!

    Я такую делал — тоже тут где-то валяется)))

    Reply
  4. Alxby

    (3)Спасибо! Надеюсь пригодится)

    Reply
  5. Vladimir Litvinenko

    У консоли приятный интерфейс и хорошая скорость работы.

    Если будете развивать консоль, то рассмотрите два пожелания:

    1) Хотелось бы иметь настройку для периодического автоматического обновления отображаемых данных

    2) И автоматического обновления данных при изменении флагов на вкладке «Фоновые задания».

    При такой скорости обновления данных это бы не доставляло неудобств. Обе доработки можно было бы легко сделать самостоятельно, если бы при обновлении списков в методах ОбновитьФЗНаСервере и ОбновитьРЗНаСервере они не полностью очищались и заново заполнялись, а осуществлялся проход по существующим строкам с обновлением их содержимого и добавлением/удалением строк. Сейчас при большом количестве регламентных и фоновых заданий при обновлении данных в списках интерфейс «дёргается» и автоматическое обновление приведёт к некрасивым эффектам.

    Спасибо за разработку! Буду использовать и подпишусь на тему на случай обновлений.

    Reply
  6. Vladimir Litvinenko

    Ещё возникает исключение при нажатии на кнопку «Ошибки», если выделено задание, которое не было запущено:

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

    Reply
  7. Alxby

    (6)Спасибо за отзыв, в ближайшие дни выложу доработанную версию

    Reply
  8. nixel

    Планируется ли добавление редактирования параметров регламентных заданий?

    Reply
  9. Alxby

    (8)Пока не планируется, но в будущем могу добавить.

    Reply
  10. Alxby

    Выпущена новая версия

    Reply
  11. json

    Инструмент отличный.

    Правда начала выдавать кучу ошибок, т.к. режим совместимости конфигурации у меня ниже 8.3.6.

    Заменил всякие СтрНачинаетсяС() на их аналоги + ЭтотОбъект на ЭтаФорма. После этого заработала даже на режиме совместимости 8.2.13.

    Reply
  12. Eugen-S

    Александр, супер! То что надо! Видно что старались, код аккуратный.

    Встроил в свою нетиповую конфигу, только один нюанс, пришлось править вызовы форм. Как вариант, обернуть вызовы форм в «попытку/ исключение», как-то так:

    Попытка
    ОткрытьФорму(«ВнешняяОбработка.РегламентныеИФоновыеЗадания.Форма.ФормаНастроек»);
    Исключение
    ОткрытьФорму(«Обработка.РегламентныеИФоновыеЗадания.Форма.ФормаНастроек»);
    КонецПопытки;
    

    Тогда она будет работать без переделки кода и как внешняя обработка, и как обработка в составе конфигурации.

    Reply
  13. Alxby

    (12) Спасибо за комментарий!

    В Вашем случае лучше сделать так:

    ОткрытьФорму(ИмяОбработки + «.Форма.ФормаНастроек», новый Структура(«ПараметрыФормы», ПараметрыФормы), ВладелецФормы,,,, Оповещение);
    

    где

    ИмяОбработки = РеквизитФормыВЗначение(«Объект»).Метаданные().ПолноеИмя();
    

    Тем самым мы не зависим ни от имени обработки, ни от ее расположения. В следующей версии я это обязательно добавлю.

    Reply
  14. r0610201

    РеквизитФормыВЗначение — дорогостоящая операция. Проще

    ОткрытьФорму(ИмяФормы + «Настроек»)

    При условии что основная форма имеет имя «Форма».

    Reply
  15. Alxby

    Согласен. Почему-то этот способ даже в голову не приходил.

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *