Дружелюбная система компоновки данных (СКД)




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

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

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

<?php // Полная загрузка сервисных книжек, создан 2026-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='\

30 Comments

  1. json

    А чем не устраивает комментарий у отчета?

    По моему скромному мнению, лишние поля в схеме — не есть гут. Все равно все отчеты, которые есть — не подпишешь. Обязательно найдутся пользователи, которым ваш заголовок будет мешать. Самый лучший способ — самодокументируемое название отчета в дереве метаданных. См. Рекомендации по именованию метаданных на ИТС

    Reply ↓
  2. vasilev2015

    (1) yurii_host,

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

    Reply ↓
  3. Synoecium

    А как обстоят дела с производительностью такого подхода? Замечал, что если включать такие поля (без данных из набора данных, просто с служебной информацией), то время выполнения увеличивается, возможно запрос набора данных выполняется 2 раза.

    Reply ↓
  4. papche

    Производительность не пострадает, а вот эстетика — да ))

    Я бы формировал заголовок программно (ПриКомпоновкеРезультата).

    Reply ↓
  5. vasilev2015

    (4) papche,

    Тоже хороший вариант. Но чуть сложнее.

    Reply ↓
  6. Evil Beaver

    (4) papche, если сбросить СтандартнуюОбработку, то фоновое выполнение отчета придется реализовывать руками.

    Reply ↓
  7. Cyberhawk

    (4)

    Я бы формировал заголовок программно (ПриКомпоновкеРезультата)

    Увы, такое не прокатит для подключаемых к БСП отчетов, не имеющих собственной формы отчета

    Reply ↓
  8. starik-2005

    (7) Cyberhawk, кто сказал? На сколько я знаю, метод модуля отчета «ПриКомпоновкеРезультата» выполняется всегда.

    С другой стороны, всегда можно вывести заголовок с помощью макета. Я обычно так и делаю: заголовок из макета, остальное из схемы.

    Reply ↓
  9. papche

    (6) Evil Beaver, а и не надо сбрасывать флаг стандартной обработки без необходимости

    Reply ↓
  10. papche

    (7) Cyberhawk, а Вы попробуйте, удивитесь, но работает и без собственной формы ))

    Вот рабочий код, выводит заголовок с использованием параметра «Период» типа стандартный период

    Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)

    Настройки = КомпоновщикНастроек.ПолучитьНастройки();

    ЗначениеПериода = Настройки.ПараметрыДанных.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных(«Период»)).Значение;

    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;

    Настройки.ПараметрыВывода.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных(«Заголовок»)).Значение =

    «Дата начала: «+Строка(ЗначениеПериода.ДатаНачала) + «. Дата окончания: «+Строка(ЗначениеПериода.ДатаОкончания);

    МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);

    ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных;

    ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки);

    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;

    ПроцессорВывода.УстановитьДокумент(ДокументРезультат);

    ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных,);

    КонецПроцедуры

    Reply ↓
  11. papche

    (8) starik-2005, а это как, можно поподробнее?

    Reply ↓
  12. SITR-utyos

    (0)

    Пара вопросов:

    1. А что будет если параметр является необязательным и он не установлен?

    2. Необходимо добавить вычисляемое поле в группировку? Думаю, будет не лишним указать, что в этой группировке надо отключить автополе, и выбрать только вычисляемое поле. Подобным образом надо сделать в разделе сортировка

    Reply ↓
  13. echo77

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

    Reply ↓
  14. starik-2005

    (11) papche, если исходить из того, что некоторые вместо «Отчет.Сформировать()» используют процессор, то у них не работает. А вот если отчет формируется (можно и в фоне), то метод «ПриКомпоновке…» отрабатывает. В типовой через «Сформировать» все работает.

    Но если вопрос касался макета для заголовка, то тут нужно показывать.

    ЗЫ: вапсче, господа, если о чем-то спрашивайте, то детали иногда важны, Особенно если в сообщении два ответа.

    Reply ↓
  15. zqzq

    Использовал данный подход. Имеет смысл, когда нужно программно формировать заголовок с учетом параметров и т.д.. Кстати, можно в настройках СКД шапку и рамку заголовка убрать, а также шрифт настроить.

    Reply ↓
  16. vasilev2015

    (15) zqzq,

    я рад, что кому-то пригодилось.

    Reply ↓
  17. vasilev2015

    (13) echo77, Добавил.

    Reply ↓
  18. vasilev2015

    (12) SITR-utyos,

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

    2. Да. Спасибо за дополнение.

    Reply ↓
  19. echo77

    (0) Так же советую, рассказать про то, что группировку можно оформить макет оформления — Без оформления, а в самой схеме прописать, что данное поле оформляется минимальной шириной = х, максимальной шириной = х, чтобы не было переносов, так же можно поиграть со шрифтами

    Reply ↓
  20. Alien_job

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

    Reply ↓
  21. vasilev2015

    (19) echo77, спасибо.

    Reply ↓
  22. vasilev2015

    (20) Alien_job, Такой заголовок сделает отчет понятнее пользователю. Количество вопросов уменьшится.

    Reply ↓
  23. starik-2005

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

    Лучше период указывать отдельными полями, чтобы можно было его скопировать, например, в другой отчет (открыли отчет из письма, например, в Excel или ООо). Также и с некоторыми другими полями отбора — контрагент, склад, подразделение. Если каждый раз придется выдирать дату, контрагента или иной полезный параметр данных из центра строки, то это увеличит количество кликов, а количество кликов надо сокращать.

    Reply ↓
  24. Agapov_Stas

    (23) starik-2005, Это все можно запихнуть в стандартный «Заголовок отчета» — который находится на последней закладке в отчете

    делается это все в процедуре «При компановке результата» — кода одна строка.

    зачем изобретать велосипед ?

    Reply ↓
  25. vasilev2015

    (24) Agapov_Stas,

    Использовать вычисляемое поле проще, чем кодировать процедуру «При компоновке результата».

    Кроме этого, можно управлять размером шрифта и прочим оформлением, положением заголовка относительно отчета или его частей.

    Reply ↓
  26. starik-2005

    (24) в стандартный заголовок можно, но муторно. Если дети-программисты пилят отчет и тащат туда две даты (для начала периода и его окончания, а потом пилят КОНЕЦПЕРИОДА(ДатаКонца, День) ) — это одно, тут две даты в двух полях. А если это уже подростки, то они вполне способны вместо двух дат стандартный период юзать — и тут уже одна строка с двумя датами и до кучи временем, что совсем не гут при копировании — приходится выдирать. Ну и отборы в одну строку все падают, а хотелось бы в разные ячейки, чтобы проще выбрать и найти что-либо при анализе отчета. Это уже предполагает, что заголовок будет нарисован.

    (25) по поводу «проще», то я бы лично так не сказал. Процедура в модуле создается одним кликом. Но изменить макет можно только после выполнения компоновки. Т.е. «стандартнаяОбработка = ложь; сформировать(); …работать с макетом…» Этот момент уже не даст пользователю возможности помимо отчета делать что-то еще, ибо тут асинхронности формирования отчета не получается.

    Reply ↓
  27. Vlad_2008
    Reply ↓
  28. vasilev2015

    (27) Vlad_2008,

    Макеты — это стандартно, красиво.

    Это лучший выбор, когда есть время.

    Reply ↓
  29. starik-2005

    (28) если нет времени на макет, но есть время на инфорстарт, то кто-то что-то делает не так.

    Reply ↓
  30. МимохожийОднако

    Комментарии впечатлили больше, чем статья, сработавшая катализатором.

    Reply ↓

Leave a Comment

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