Итоговая сумма в динамических списках (список документов, список справочников)




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

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

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

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

22 Comments

  1. Tokiy

    Плюсуем кому понравилось и пригодилось! 😉

    Reply
  2. WKBAPKA

    Сразу вопросы:

    1. Зачем СОКРЛП()? У текстовых реквизитов установлена фиксированная длина?

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

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

    Правда, что то я сумневаюсь, что если у документа есть реквизит «Сумма», что по нему в подвале нельзя получить итоговое значение.

    Опять же, почему нельзя посчитать итог в запросе?

    Вообщем много почему!!!

    Reply
  3. Поручик

    Вот именно что, почему в событии ОбновлениеОтображения(), а не в ПриПолученииДанных?

    Reply
  4. WKBAPKA

    2(3): +1

    Reply
  5. artbear

    Каждый раз в цикле юзать ДокументСписок.Отбор[Индекс] совсем не гуд 🙁

    Reply
  6. WKBAPKA

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

    Reply
  7. Yashazz

    Советую изучить ИсточникДанных и ОписаниеИсточникаДанных, при использовании которых данная задача превращается в тривиальную.

    Reply
  8. Kom-off

    (7)+

    Reply
  9. Tokiy

    (2) 1 — Метод СокрЛП() используеться для перестрахования, Ресурсов много он не ест, зато дает стопроцентный результат (возвращает ТЕКСТ без ПРОБЕЛОВ) что для запроса и нужно. 2 — при большом объеме базы рекомендую вешать не в предопределенную процедуру ОбновлениеОтображения(), а на кнопку, чтоб пользователь рассчитывал сам эту сумму. Или если есть вариант получше, я с радостью выслушаю.

    Reply
  10. Tokiy

    (3) Потому что предопределенной процедуры ПриПолученииДанных() нет в форме списка документа. А я повторяюсь что это код для получения итоговой суммы в динамических списках (список документов, список справочников).

    Reply
  11. Tokiy

    (5) есть другие варианты с радостью выслушаю 🙂

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

    Reply
  12. Tokiy

    (6) Век живи, век учись. «Семерочником» всегда лучше быть чем двоечником 😀

    А если серьезно, то не вижу логики в ваших словах. Из бывших «семерочников» часто получаются настоящие «восмерочники».

    Reply
  13. Tokiy

    (7) Спасибо! Пригодился ИсточникДанных, с помощью которого удалось избежать лишнего цикла. +1

    Reply
  14. artbear

    (13) Уже намного лучше.

    1. Для оптимизации (все-таки код будет очень часто вызываться) лучше весь блок до ПостроительЗапроса.Выполнить() вынести в отдельный метод, вызываемый в ПриОткрытии.

    2. Совсем нелогично использование запроса и выгрузки в ТЗ и подсчет суммы 🙁

    считай итоговую сумму сразу в запрос 🙂 — будет совсем шустро.

    Reply
  15. artbear

    Кстати, автор прав, а (3) нет 🙂

    Reply
  16. Поручик

    (15), (10) Извините-с, х..ню-с сморозил. 🙁

    Reply
  17. artbear

    (0) Автор, прочти http://www.kb.mista.ru/article.php?id=471

    думаю, станет более понятна схема с построителем и динамическим списком.

    Reply
  18. Tokiy

    (17) Нормальная статейка, подтвердил свои знания )))

    Reply
  19. artbear

    На (14) обрати внимание

    Reply
  20. Tokiy

    (19) Да, согласен, что часть кода можно вынести в процедуру ПриОткрытии(), только до строки «ОписаниеИсточникаДанных= Новый ОписаниеИсточникаДанных(ДокументСписок);» иначе не будет обновляться итоговая сумма. И итог можно в запросе рассчитать. 🙂

    Reply
  21. tka4enk0

    Для динамического списка с произвольным запросом работает (управляемые формы)??? У меня почему-то не взлетело.

    ОписаниеИсточникаДанных= Новый ОписаниеИсточникаДанных(ДокументСписок);

    ДокументСписок — Это элемент формы???

    Reply
  22. Tokiy

    (21) tka4enk0, для управляемых форм этот код не пойдет.

    ДокументСписок — это тип «ДокументСписок[ИмяДокумента]».

    Reply

Leave a Comment

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