<?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='\
глРаспечататьТаблицу<<?>>(тзСсылок);
{C:TEMPПОИСКССЫЛОК.ERT(361)}: Процедура не обнаружена (глРаспечататьТаблицу)
глРаспечататьТаблицу<<?>>(тзСсылок);
{E:!1C_BASEEXTFORMS1POISKSSYLOK.ERT(361)}: Процедура не обнаружена (глРаспечататьТаблицу)
Извиняюсь за дубль — не обновил страницу.
Ошибка обработки запроса:
SELECT DISTINCT
:Объект As [Объект $Справочник.Контрагенты]
,Tab.DOCID As [Ссылка $Документ]
,’Субконто’ As Реквизит
,’Проводка’ As Метаданные
,J.IDDOCDEF AS Ссылка_вид
, CASE :Объект
When
Tab.DTSC0 then ‘Дт1’
When
Tab.KTSC0 then ‘Кт1’
When
Tab.DTSC1 then ‘Дт1’
When
Tab.KTSC1 then ‘Кт1’
When
Tab.DTSC2 then ‘Дт2’
When
Tab.KTSC2 then ‘Кт2’
When
Tab.DTSC3 then ‘Дт3’
When
Tab.KTSC3 then ‘Кт3’
END As Субконто
FROM
_1SENTRY As Tab
INNER JOIN _1sjourn J On J.IDDOC = Tab.DOCID
where (Tab.DTSC0 = :Объект And Tab.VDTSC0 in (450)) OR (Tab.KTSC0 = :Объект And Tab.VKTSC0 in (450))
OR (Tab.DTSC1 = :Объект And Tab.VDTSC1 in (450)) OR (Tab.KTSC1 = :Объект And Tab.VKTSC1 in (450))
OR (Tab.DTSC2 = :Объект And Tab.VDTSC2 in (450)) OR (Tab.KTSC2 = :Объект And Tab.VKTSC2 in (450))
OR (Tab.DTSC3 = :Объект And Tab.VDTSC3 in (450)) OR (Tab.KTSC3 = :Объект And Tab.VKTSC3 in (450))
State 42S22, native 207, message [Microsoft][ODBC SQL Server Driver][SQL Server]Invalid column name ‘DTSC3’.
(1), (2). Прошу прощения не отвязал от конфгурации.
(3) — Максимально количество субконто не определялось, стояло 4 по умолчанию.
Добавил недостающую процедуру вывода таблицы значений — удобно, если не хочется делать печатную формую
Поправил определение количества субконто.
В процедуре НайтиРеквизитыСсылок в цикле по субконто, нужно делать цикл от 1 по КолвоСубконто-1
и в ДопКолонке писать
When
Tab.DTSC»+Субконто+» then ‘Дт»+(Субконто+1)+»‘
When
Tab.KTSC»+Субконто+» then ‘Кт»+(Субконто+1)+»‘»;
Тогда взлетит.
(6) Точно 🙂 Затупил… Хотя у меня работает с таким запросом.
А что в колонке Ссылка_вид?
Если ссылка найдена в движении регистра, то там какое-то число, в остальных строках там пусто.
1. Еще бы надо проверять наличие таблицы _1sentry и, в зависимости от ее наличия, обрабатывать или пропускать строки 317-340. В ТиС и ЗиК ее нет и получаем ошибку.
2. В _1sentry нумерация субконто начинается с ноля, т.е. при 3-х субконто поля будут называться DTSC0, DTSC1, DTSC2. А в обработке они начинаются с единицы, в связи с чем имеем ошибку — Недопустимое имя столбца «DTSC3». Соответственно, строку 330 надо изменить на
О, пока разглядывал, тут уже написали. Но Boog (6) не до конца прав — см. мое (9), п.2.
(10) В принципе то же самое, только у меня первые субконто задаются до цикла по остальным, тогда цикл с 1.
Добавил определение наличия таблицы, поправил максимально количество субконто, (6)поправил нумерацию субконто.
(8) Ссылка_вид содержит идентификатор вида документа для типизации документа в запросе. Если идет запрос по регистрам — в качестве сылки возвращается документ, который делал движения. В остальных случаях если ссылка не документ, то и вид документа не нужен, соответственно он пустой.
Это служебное поле, которое в принципе можно прятать.
С проверкой на ведение бух. учета в базе вообще — согласен.
По поводу цикла от 0 по КолвоСубконто-1:
там перед циклом определяются DTSC0 и KTSC0. Отдельно. (и условия для них).
(11) впопыхах не заметил
(12) угу, теперь летает
Ошибка обработки запроса:
SELECT DISTINCT
:Объект As [Объект $Справочник.Фирмы]
,Tab.ID As [Ссылка $Справочник.Фирмы]
,’Родитель’ As Реквизит
,’Справочник.Фирмы’ As Метаданные
FROM
$Справочник.Фирмы As Tab
where Tab.PARENTID = :Объект
State 42S22, native 207, message [Microsoft][ODBC SQL Server Driver][SQL Server]Invalid column name ‘PARENTID’.
—————————
Ошибка обработки запроса:
SELECT DISTINCT
:Объект As [Объект $Справочник.Фирмы]
,Tab.DOCID As [Ссылка $Документ]
,’Субконто’ As Реквизит
,’Проводка’ As Метаданные
,J.IDDOCDEF AS Ссылка_вид
, CASE :Объект
When
Tab.DTSC0 then ‘Дт1’
When
Tab.KTSC0 then ‘Кт1’
When
Tab.DTSC1 then ‘Дт2’
When
Tab.KTSC1 then ‘Кт2’
When
Tab.DTSC2 then ‘Дт3’
When
Tab.KTSC2 then ‘Кт3’
END As Субконто
FROM
_1SENTRY As Tab
INNER JOIN _1sjourn J On J.IDDOC = Tab.DOCID
where (Tab.DTSC0 = :Объект And Tab.VDTSC0 in ()) OR (Tab.KTSC0 = :Объект And Tab.VKTSC0 in ())
OR (Tab.DTSC1 = :Объект And Tab.VDTSC1 in ()) OR (Tab.KTSC1 = :Объект And Tab.VKTSC1 in ())
OR (Tab.DTSC2 = :Объект And Tab.VDTSC2 in ()) OR (Tab.KTSC2 = :Объект And Tab.VKTSC2 in ())
State 42000, native 102, message [Microsoft][ODBC SQL Server Driver][SQL Server]Incorrect syntax near ‘)’.
(14)
Не был предусмотрен вариант справочников с одним уровнем.
Не был предусмотрен вариант остутствия объекта в видах субконто.
Заголовок = глСтрРасставитьПробелы<<?>>(тз.ИмяКолонки(НомерКолонки));
{D:ПОИСКССЫЛОК.ERT(33)}: Функция не обнаружена (глСтрРасставитьПробелы)
(16) Извиняюсь, выгрузил старую версию. Сейчас уже лежит новая.
18. Очень интересно сделано. Код понравился ))) +
Как раз искал похожую обработку. Все вроде бы хорошо но два нюанса. Стандартная функция НайтиСсылки() в большинстве случаев работает у меня быстрее но если в этой обработке убираю лишние метаданные тогда она работает намного быстрее чем стандартный механизм. Но эта обработка не учитывает метаданные где есть реквизиты неопределенного типа!
Новая версия. Теперь учтены реквизиты неопределенного типа (Спасибо maxim_ro).
(19) Спасибо за указанный недочет. Для собственного пользования обработка давно уже доработана, здесь не обновил.
Самое большое время тратится на запрос по таблице проводок. Если эта таблица не интересует — можно смело закомментировать. Вообще обработка и создавалась для того чтобы можно было искать ссылки выборочно а не по всем метаданным.
Для реквизитов неопределенного типа в отчете для документа стоит
сзНеопределенных.Установить(«Документ», «‘A1’+»);
т.е. в запросах получается типа того
where Tab.sp2265 = ‘A1’+’ 7K’+’ 65GAE ‘
Провел трассировку стандартного метода НайтиСсылки() и там во временную табл. для документа передается ‘O1’, т.е. строка должна получиться вида
where Tab.sp2265 = ‘О1’+’ 7K’+’ 65GAE ‘
Может подскажете как всетаки корректно определить правильное значение для документа или справочника.
(22) проверил сейчас. Действительно — верно ‘О1’. Видимо при разработке недостаточно тестировал.
Версия обновлена.
Кстати я для справочника не проверял.
И еще меня это очень заинтересовало хочу доработать, а пока просто подкину идею по ускорению.
Если ищем ссылки на документ, то вероятность того, что на данный (искомый) документ встретятся ссылки в документах или на регистрах раньше самого документа чрезвычайно мала. А значит нет смысла проверять всю таблицу в запросе, а нужно отсекать по дате времени документа. Хотя не спорю могут быть специфичные ситуации, когда документ передвигают по датам и времени.
Но если добавить фильтры по времени, то на больших базах для документов поиск можно сократить в разы