Разработка отчета СКД с использованием заглушек наборов данных




Принцип обмена данными из 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='\

14 Comments

  1. roofless
    Дополнительным плюсом в таком подходе является то, что если в базе нет всех нужных нам данных, то разработка не задерживается, мы можем сделать самую трудную работу без них.

    самое трудное — это добавить в базу нужные данные =(

    перефразирую — «Если в базе нет нужных нам данных, то лепим заглушки», верно?

    Прототип запроса писать нужно, имхо. Иначе, как мы узнаем, что этих данных нет?) сразу наверное абстрагироваться не стоит

    Reply
  2. json

    (1) roofless, часто бывает так, что данных в базе нет, потому что их туда трудно набить. Например, данные добавляются в регистры документами, которые еще находятся на стадии разработки. Или данные добавляются в регистр в результате сложного расчета (например, по себестоимости). Или я пытаюсь добавить данные в таблицы базы и начинают сыпаться ошибки, которые ко мне не имеют отношения. Или какие-нибудь ограничения по правам. Или требуется ввести еще кучу предварительных документов, чтобы добавить записи в нужный тебе регистр при проведении. Тогда заглушки очень даже полезны.

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

    Но если отчет простой, и структура вывода линейная, и изначально понятно какие поля должны быть в запросе — то не имеет смысла заморачиваться с заглушками

    Reply
  3. Yashazz

    Лепя заглушки, не забывайте о потенциально пустых реквизитах и о реквизитах составного типа… Особенно весело делать это для характеристик)

    Reply
  4. json

    (3) Yashazz, часто такое бывает?

    Reply
  5. chmv

    Неправильный подход изначально

    Reply
  6. json

    (5) chmv, спасибо за проявленный интерес.

    Не могли бы поподробнее уточнить, что конкретно вы считаете неправильным?

    Reply
  7. Азбука Морзе

    Ну не знаю… По-моему, чтобы получить недостающие данные, гораздо нагляднее да и проще использовать таблицы значений в качестве параметров к запросу.

    Reply
  8. Yashazz

    (4) как будете делать заглушку для субконто?

    Reply
  9. json

    (8) Yashazz, если я правильно понял вопрос, то его можно переформулировать так:

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

    ответ — можно попробовать возвращать поле через ЗНАЧЕНИЕ(Предопределенное значение или пустая ссылка). Но нужно смотреть по ситуации и, возможно, в некоторых случаях методика, описанная в данной публикации, вам не подойдет

    Reply
  10. Quasar

    (7) Азбука Морзе, а в чем принципиальное отличие? Да и к тому же данный метод позволяет написать заглушку 1 раз прямо в тексте запроса. А не подкидываться каждый раз с формированием таблицы значений и передачей ее в качестве параметра.

    Reply
  11. Onwardv

    Да, удобно.

    Я тоже такой подход использую.

    Но заглушкой называю другое :). : Конструкцию вида ЛОЖЬ И

    Когда делаешь отчет по ТЗ(тех.задание), где множество временных таблиц, а потом тз поменялось и какая-либо выборка уже не нужна (возможно вернут). Вот там и добавляем в «где» эту заглушку.

    ГДЕ ЛОЖЬ И
    старые условия.

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

    Также использую для поиска критичных для быстродействия соединений при оптимизации разветвленных запросов. Например, есть запрос с множеством левых соединений, который пытаемся оптимизировать. Берем и отрубаем самый подозрительный заглушкой :

    …..

    Левое соединение регистрСведений.НашСуперРегистр.Срезпоследних()
    по ЛОЖЬ И
    старые условия

    ….

    если скорость выполнения увеличилась не существенно, тогда заглушку убираем и ставим на другое подозрительное.

    Т.е. ищем действительно самые долго выполняющиеся соединения и оптимизируем их, а не все подряд.

    Reply
  12. herfis
    Трудность заключается в том, что нам изначально непонятна структура полей, которые нужно получить из наборов данных, какие поля будут вычисляемыми, можно ли посчитать ресурсы формулами или же их придется вычислять в запросах.

    Фигня какая-то. Никогда таких трудностей не возникало.

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

    Какие, нафиг, итерации? Откуда? Только не стоит вещать, что я не работал с «по-настоящему сложными отчетами» или что я какой-то там уникум.

    Единственную пользу вижу — возможность отладить в консоли схему, в которой будут использоваться в т.ч. и «боковые» наборы данных (из ТЗ, например). Тогда в самом деле эффективно воткнуть «заглушку» в виде набора аналогичной структуры, которую в «боевом» варианте можно поменять «одним движением».

    Reply
  13. json

    (12) herfis, спасибо за отзыв.

    В статье описан прием, который лично мне помогал решать большое количество СЛОЖНЫХ задач.

    Кроме того, перед написанием статьи я поделился им с несколькими коллегами. Некоторые из них тоже стали его применять, а некоторым этот прием не подошел. В общем это нормально — всем угодить невозможно. Кроме того несколько пользователей Инфостарта также нашли описанный способ полезным для себя. Данная статья выкладывалась в первую очередь ради них.

    Reply
  14. hromovanton

    (11) Onwardv, спасибо за пример с заглушкой в соединениях запроса!

    Reply

Leave a Comment

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