<?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='\
Спасибо
А что за конфигурацию вы используете, где есть Допустимое число дней задолженности?
(2) karpik666, это типовой реквизит справочника «Договоры контрагентов» в УПП, нами же был добавлен реквизит «Контроль оплаты в рабочих днях» (тип булево).
Думаю в бухгалтерии такое значение может выполнять доп. свойство договора.
(3) а сколько по времени работает запрос, к сожалению у себя не могу протестировать, как вижу здесь вообще не стоит отбор на календарь, да и на реализации. А что если реализация будет сделана в выходной день? тогда у вас запрос вернет null. И левое соединение никак не обрабатывается, тогда уж лучше сделать внутреннее. И еще один нюанс, если дата реализации 14.10.2015 и кол-во дней просрочки 90 дней, то какую он дату покажет как просрочку?
(4) karpik666, хорошее замечание. Здесь я описал возможный вариант реализации.
1. Отбор на календарь не стоит, т.к. в нашем случае актуальный долг мог возникнуть несколько лет назад. В замере производительности запрос на календарь и соединение временной таблицы друг с другом занимает 5-7 мс.
2. Если реализации выпадает на рабочий день, то можно немного подправить запрос в части соединения.
Т.е. в этом случае мы выбираем следующий рабочий день от даты реализации. Внутреннее соединение не есть хорошо, т.к. лучше увидеть неверно рассчитанную дату возникновения просрочки, чем не увидеть её вовсе.
Показать
(4) karpik666, но в любом случае, первая таблица к документам реализации не означает получение задолженности. Здесь это всего лишь пример. Как вы получите первоначальную таблицу зависит от вас.
P.S. В нашем случае дата возникновения долга по разным условиям договора может меняться (долг считается от каждой отгрузки, от полной отгрузки, от определенной даты, от даты подписания документов и др.) .
(6) можно поставить отбор на календарь по минимуму из даты реализаций, чтобы не получать записи ненужного периода. Так-то запрос еще дольше будет работать =) И еще остается вопрос с реализациями на конец года, так как производственный календарь утверждают где-то в декабре, то и получается, что с такими реализациями будет проблема, так как на момент проверки записей производственного календаря еще не будет.
Это всего один из возможных способов. Довольно экономный, кстати, с точки зрения расхода ресурсов. «Нарастающий итог» для расчета порядкового номера рабочего дня считается один раз, а затем многократно используется. Хорошо бы индексы еще к таблице порядковых номеров рабочих дней построить. И можно было бы соединять не с рабочими днями, а с выходными, которых меньше. Или вообще с исключениями (праздниками и переносами).
http://infostart.ru/public/99507/ Банковские дни запросом
http://infostart.ru/public/166349/ Добавить к дате рабочие дни в запросе
http://infostart.ru/public/320887/ Расчет рабочих дней в запросе <<<- Здесь ровно тот же способ!!!
http://infostart.ru/public/338386/ Расчет банковских (рабочих) дней (Оригинальный способ)
http://infostart.ru/public/358354/ Прибавление банковских дней к дате в запросе
Для полного совершенства публикации не хватает ссылок на другие публикации по той же теме.
Вообще приведение ссылок на другие публикации той же темы — правило хорошего тона, использование которого приносит и автору и читателям много пользы, дает «кумулятивный» эффект. — Не сделать ли этот блок в публикации обязательным?
(7) karpik666, как вариант можно заполнить производственный календарь по тем праздникам и выходным, по которым есть информация. Как только правительство скажет что куда переносится, то так и сделаем.
(8) ildarovich, объективно, индексы нужны.
Просьба указать для каких конфигураций подходит запрос.
В УТ 10.3 точно подходит, есть регистр нужный.
Подходил ли для УПП, БП?
(10) pvlunegov, это пример реализации в расчете банковских дней от какой-то даты в запросе.
Подходит для УПП и БП (вроде там тоже есть такой регистр), в других конфигурациях, если есть подобный регистр, то можно использовать.
А на сколько лет впередназад обычно заполнены регистры, содержащие данные календаря в околотиповых конфигурациях?
Запрос (0) не совсем правильный, кстати. Если документ реализации был в выходной или праздничный день, индекс этого дня (ИндексДатыДолга) отсутствует, и, следовательно, не определяется дата возникновения просроченного долга.
Исправления этого могут быть различные, могу дать свой работающий вариант, если это еще кому-то интересно.
(13) kapustinag, почему бы и нет. Внесу исправление в статью от вашего имени.
(14) После формирования временной таблицы ВТ_РеглКалендарьСИндексами я добавил формирование еще одной временной таблицы;
ВЫБРАТЬ
ВТ_РеглКалендарьСИндексами.ДатаКалендаря,
ЕстьNULL(Таб.ДатаКалендаря,КОНЕЦПЕРИОДА(ВТ_РеглКалендарьСИндексами.ДатаКалендаря,ДЕНЬ)) КАК СледующаяРабочаяДата,
ВТ_РеглКалендарьСИндексами.ИндексРегламентированногоКалендаря
ПОМЕСТИТЬ ВТ_РеглКалендарьСИндексами2
ИЗ ВТ_РеглКалендарьСИндексами КАК ВТ_РеглКалендарьСИндексами
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_РеглКалендарьСИндексами КАК Таб
ПО ВТ_РеглКалендарьСИндексами.ИндексРегламентированногоКалендаря = Таб.ИндексРегламентированногоКалендаря-1
;
Таким образом, строки этой временной таблицы содержат, кроме даты строки, дату следующего рабочего дня.
После этого запрос, формирующий временную таблицу ВТ_СИндексом, меняем вот таким образом:
ВЫБРАТЬ
ВТ.Ссылка,
ВТ.Дата,
ВТ.ДнейОтсрочкиДолга,
ВТ_РеглКалендарьСИндексами.ИндексРегламентированногоКалендаря КАК ИндексДатыДолга
ПОМЕСТИТЬ ВТ_СИндексом
ИЗ
ВТ КАК ВТ
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_РеглКалендарьСИндексами2 КАК ВТ_РеглКалендарьСИндексами
ПО ВТ.Дата >= ВТ_РеглКалендарьСИндексами.ДатаКалендаря И
ВТ.Дата < ВТ_РеглКалендарьСИндексами.СледующаяРабочаяДата
;
Всё.
При формировании поля «следующая рабочая дата» использую конструкцию ЕстьNULL(…) — для того чтобы в последней строке календаря это поле тоже было заполнено.
Особого падения производительности не заметил. Но и точных замеров не делал.
Может быть, пойдет и вариант, когда вместо дополнительной временной таблицы получаем дату следующего рабочего дня сразу при формировании ВТ_РеглКалендарьСИндексами — ценой еще одного внутреннего соединения.