Расчет банковских (рабочих) дней (Оригинальный способ)




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

17 Comments

  1. WhiteOwl

    Занятная идея!

    Reply
  2. vasyak319

    Жесткач. Хорошо, что современные машины делают по несколько миллиардов операций в секунду и их не убить даже такими алгоритмами.

    Reply
  3. Alien_job

    (2) vasyak319, да ладно — регламентные отчеты тоже свои настройки в макетах хранят. Хотя в циклах они их, конечно, не получают.

    Reply
  4. vasyak319

    (3) Alien_job,

    Хотя в циклах они их, конечно, не получают

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

    Плюс отдельная премия Дарвина за вычисление перебором дней (особенно клёво, когда начальная дата пустая — тогда это over 700 тыщ итераций), что, впрочем, вытекает из остальных косяков алгоритма.

    Reply
  5. AganinEvgeniy

    Идея и правда не плоха … но согласен с Василием, легче выбирать 20 отклонений в год и плюсовать их к номеру дня недели или что-то подобное намудрить, чем перебором обходить 365 дней.

    Reply
  6. fzt

    А почему бы и нет. Идея довольно простая и конфа не снята с поддержки.

    Как улучшить:

    1) Формируем всю эту радость в екселе.

    2) К xls файлам можно делать полноценные SQL запросы, через драйвер ODBC (в поставке любой винды).

    Экономия кучи машинного времени.

    Reply
  7. Rustig

    (4) задача решается на файловой базе, период расчета неустойки три года: с начала 2013г по текущий день 2015 г включительно — летает «на ура!» — проблем с производительностью нет. по поводу мелких недочетов — тут каждый сам решает для себя — у меня дата начала не может быть пустой — изначально стоит проверка в другой процедуре. такие дела. за замечания спасибо: может быть другим пригодится.

    Reply
  8. Rustig

    (4) ваше замечание заставило меня задуматься: почему же при таком алгоритме проблем с производительностью не возникает? Оказывается, это следует из специфики самой постановки задачи — расчета просрочек: условно говоря, просрочка считается от ДатыОтгрузки до ДатыСледующегоСобытия (или даты оплаты или даты следующей отгрузки). Таким образом для каждой реализации (отгрузки) возникшая пара «ДатаНачала»-«ДатаОкончания» является «коротким» периодом, то есть к примеру от 14.03.2014 до 23.03.2014 прошло 9 календарных дней — в этом периоде определяется 6 банковских дней. То есть по сути цикл в алгоритме состоит из 9 итераций — проверяем каждый день является ли он банковским. Еще раз спасибо за замечание!

    Reply
  9. Rustig

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

    Reply
  10. vasyak319

    (8) просто у вас объём маленький, а современные машины сцуко быстрые, так что если алгоритм, который при нормальной реализации отработал бы за микросекунду, работает в тысячу раз медленнее, вы этого один чёрт не заметите. Но это всё равно плохо, потому что миллисекунда тут, миллисекунда там, а в итоге документы по полминуты проводятся.

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

    Кроме того, это сейчас ваша процедура используется исключительно для отсрочки 10 дней. Другая задача появится, где тоже нужны будут банковские дни, и вы её либо заново переписывать будете, либо она будет у вас тормозить.

    Reply
  11. vasyak319

    (9) т.е. передавать весь массив данных серверу — пусть развлекается? Снова неоправданная жестокость. На самом деле, если у вас всё ограничено известным периодом (а у вас всё как минимум ограничено периодом, для которого у вас есть календари), то вычисление каждой отсрочки можно свести к разности двух элементов одного массива.

    Reply
  12. Rustig

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

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

    Reply
  13. vasyak319

    (12) кстати, вот мне это сразу показалось странным, но я вам поверил, что в БП 2.0 нет производственного календаря. Сейчас решил таки посмотреть — он там есть. Тогда зачем вообще это всё?

    Reply
  14. Rustig

    (13) что за объект метаданных?

    Reply
  15. Rustig

    (13), (14) есть такой — регистр сведений Регламентированный производственный календарь. Ну, отлично! что ж сказать? не знал, что такой есть.

    Reply
  16. b-dm

    А все равно публикация классная. Мне нпонравилось и решение и описание. Плюс.

    Reply
  17. DDos76

    Реально способ оригинальный. За способ поставил +!

    Следующий этап — календарь будет храниться в экселе, сначала по OLE (Пардон COM) попробуем оттуда забирать.

    К xls файлам можно делать полноценные SQL запросы, через драйвер ODBC (в поставке любой винды). — это не так интересно.

    Если будет медленно — там и до PegExp рукой подать. Разбор файла .XLS средствами 1с так сказать.

    С 1 Апреля!

    Reply

Leave a Comment

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