<?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='\
Прикольно!
Возможно стоит добавить еще детализацию показателей по измерениям, например номенклатура или склад. Поясню: в документе заменили одну позицию номенклатуры другой с той же ценой, сумма не поменялась. Изменили склад — сумма также не изменилась.
А вообще — отлично!
Забыл сказать, что на мысль использовать данный подход для сравнения движений документов в двух базах меня натолкнула статьяСравнение двух строк. Функция . А то, что метод дихотомии является популярным методом поиска ошибок, подтверждается, например, в статье Теория поиска ошибок 🙂 .
(1) ardn, это хорошее предложение — сделать настраиваемый фильтр по всем измерениям анализируемого регистра. — Подумаю над этим.
Идея шикарная. Автору — мои аплодисменты.
Но в методике по описанию сразу сразу несколько проблемных моментов:
1. Интервал сравнения оборотов — 1 месяц. Документ перенесён с 10-го числа на 20-е. При сравнении оборотов за 1 месяц ничего не произошло (документ не поменял период сравнения оборотов). Но другой документ за 5-е число поменял обороты.
При этом в пределах месяца получаем одну ошибку (на 1 копейку от документа за 5-е число), а при поиске этого документа делим интервал пополам и в каждом интервале получаем ошибку на много тысяч (от перенесённого документа). А если нет документа с изменёнными оборотами за 5-е число — то перенос документа с 10-го на 20-е вообще никак не обнаруживается.
2. Давным давно, много десятилетий назад на заре компьютеризации нашей цивилизации, было доказано, что в подобных поисковых системах с точки зрения производительности гораздо выгодней делить интервал не пополам, а по методу золотого сечения.
«На фиг 1» интересно пишется )))
(5) Так и было задумано.
(4) По порядку
1) Отчет показывает все эти изменения в достаточно понятном виде. В демо-базе БП в феврале 2009 оказались как раз документы в этих датах и были внесены указанные изменения. Вот, что показал отчет. Все вроде бы логично и проблемы не видно.
2) Здесь Вы путаете с методом поиска экстремума функции, где «замер» показывает не наличие-отсутствие искомого объекта на интервале поиска, а значения функции (их нужно два), которые затем сравниваются, чтобы было понятно с какой стороны экстремум и куда идти. А бинарный поиск — это немного другое. Да просто попробуйте сыграть в «угадай число» с ответами «больше-меньше» и самая эффективная стратегия родится сама собой.
(4) FractonKireyev,
1) Здесь сравниваются итоги, поэтому можно придумать много подобных ситуаций. Например, отличающиеся реквизиты в движениях или изменение суммы документа и ввод сторнирующих эти изменения проводок в том же месяце. Достоверность принесена в жертву скорости работы.
Если нужно полное сравнение движений, проще выгрузить движения в табличный документ в одинаковом виде и сравнить через «сравнение файлов» или любую другую DIFF-программу.
2) Если я правильно помню, метод золотого сечения предпочитают методу дихотомии, потому что для него на каждом шаге нужно вычислять значение функции в одной новой точке, а не в двух, как при дихотомии. В данном случае, значение функции — остатки на границах периода, которые платформа берет из таблицы итогов (по крайней мере, по месяцам), что наоборот выгоднее по производительности, чем получение остатков на произвольную точку внутри месяца, как будет при делении по золотому сечению. Внутри же месяца действительно выгоднее будет использовать золотое сечение.
UPD: внутри месяца будет быстрее сразу сравнивать таблицы движений, так как они все равно будут использоваться при расчете остатков на произвольную дату внутри месяца.
(8) MadMix,
1) Все так, но я бы сказал, что в жертву скорости работы принесена не достоверность, а полнота контроля. Полноту можно увеличить, если контролировать итоги, развернутые по измерениям.
2) Метод золотого сечения здесь совершенно не причем. Значения функции в нем вычисляются для поиска точки, в которой функция достигает максимума (или минимума). Как это связать со сравнением оборотов? Предлагаете искать максимум или минимум чего?
То есть золотое сечение — для совершенно другой задачи, хотя по структуре методы похожи.
То, что рассчитанные итоги не помогают определять сумму оборотов внутри месяца — это так. Но все равно метод дихотомии будет быстрее и внутри месяца, когда отличий сравнительно мало. Потому, что вместо построчного сравнения больших таблиц, перегоняемых из базу в базу, мы сравниваем несколько контрольных сумм, получаемые двумя запросами.
Это как сравнить два гигабайтных файла, хранящихся на разных компьютерах. Можно их сравнить побайтно, передав файлы по сети. Это долго. А можно рассчитать и сравнить только контрольные суммы файлов.
(9) здесь функцию можно представить как дискретную функцию:
f(x) = 1, когда есть отличия между оборотами в базах за период от НачалоПериода до НачалоПериода + x;
иначе f(x) = 0.
Поэтому вполне можно применять любые методы поиска экстремума.
(10) MadMix, метод золотого сечения требует, чтобы функция была УНИМОДАЛЬНОЙ. А предлагаемый метод находит любое количество отличий.
Но пусть даже отличие только одно…
Пусть начальный отрезок [0, 1]. Отличие в точке 0.001. Выберем х1 < х2 по правилу золотого сечения. f(x1) = 1, f(х2) = 1. По методу золотого сечения нужно будет взять в качестве следующего интервала [0, x2]? А по здравому смыслу [0, х1]! Дихотомия сузит интервал неопределенности до 0.001 за десять шагов, а золотое сечение — за 15 шагов (1.618 #k8SjZc9Dxk 15 = 1363).
(11) окей, попробую разжевать. Метод дихотомии позволяет найти отличия за наименьшее число итераций, что отнюдь не означает максимальную скорость. Метод золотого сечения позволяет сократить число вычислений значения функции (именно это занимает наибольшее время, как правило).
В вашем же примере — при дихотомии нужно будет вычислить значение функции 19 раз (по 2 раза на каждой итерации и 1 раз на первом шаге). При использовании золотого сечения — только 15 раз.
Проблема с поиском всех отличий тоже решается достаточно просто.
(12) MadMix, давайте разжевывать до конца…
Если функция унимодальна (отличие только одно), то при дихотомии на одной итерации потребуется ОДНО вычисление функции — делим интервал надвое и проверяем (сравниваем обороты) правый интервал: если отличие есть, выбираем в качестве следующего его, иначе — берем левый интервал. Так что вычислений функции — 10.
И про это
тоже поподробнее, пожалуйста.
(12) Ну и вообще, чтобы спор не был голословным, может быть предложите свою функцию для сравнения двух строк методом золотого сечения? Это простая задача из статьиhttp://infostart.ru/public/174530/ . Можно будет сравнить быстродействие не на словах, а на деле. В комментарии http://forum.infostart.ru/forum24/topic80332/message852380/#message852380 есть обработка, куда сможете вложить свою функцию. Мне кажется, при попытке применить золотое сечение к этой задаче на практике, сразу станет ясно «той ли системы ваши гранаты».
Жееесть -))
Ребята, ваш спор — это жесть ;-))
(15) Нормальный спор, мягкий вполне себе. Только студента куда-то след простыл, когда его попросили показать домашнее задание…
(0) Хорошая обработка, давным-давно я также делал аналогичную работу (есть в профиле).
Но у тебя ИМХО намного мощнее, лучше и удобнее получилось.
Молодец.
Спасибо!
(17) Спасибо за информацию о разработках на похожую тему. Кроме ВашейСравнение остатков или оборотов двух регистров — накопления или бухгалтерии, версия 2.3 нашел в ее обсуждении вот такую Сравнение остатков и оборотов регистров накопления и бухгалтерии двух баз через COM .
Появилась еще одна обработка для решения той же задачи:Сравнение оборотно-сальдовой ведомости двух баз и поиск различий в операциях (проводках документов) . Разница в том, что там сначала строится ОСВ, а потом находятся различия путем последовательного сравнения проводок по счету. Минус такого подхода — в бОльших затратах времени, а плюс — в том, что используемые формы отчетов имеют привычный вид. Также там упоминается обработка, взятая за основу: http://infostart.ru/public/167127/ .
Сравнение регистров бухгалтерии с копией базы для БП 2.0 на платформе 8.2 .
Предлагаемая здесь обработка фактически работает не со всей ОСВ, а с ее последней итоговой строчкой (хотя можно отбирать счета и показатели). Поэтому идеальная обработка все же должна быть разделена: первая должна сравнивать обороты за весь период в развороте по всем счетам и измерениям, а вторая — дихотомией находить собственно причины расхождений по ранее определенным измерениям. Иначе можно не заметить изменения аналитики в проводках.
…
В коллекцию ссылок еще отчет по той же теме:
(0) да, это тоже сильно! отличная статья
Ваш отчет на регистрах накопления в ЗУП 2.5 не работает. Скрин ошибкиhttp://itmages.ru/image/view/1843779/69e9f753
(21) Dach, все работает и дело не в конфигурации. Этот отчет принципиально требует заданного интервала анализа, а вы его не задали — отчету нечего делить пополам, вот он и вылетает. Нужно будет вставить проверку на непустые значения!
(22) ясно… в недрах отчета не ковырялся, скажите, он сравнивает результаты, хранящиеся в виртуальных таблицах остатков и оборотов или сам агрегирует суммы? Потому что в ситуации, когда в одной из баз кривые итоги… далее можно не продолжать….
(23) Dach, отчет работает с виртуальными регистрами, а они уже агрегируют суммы. Внутри интервалов хранения итогов (месяц) работа с виртуальными регистрами будет опираться не только на сами итоги, но и на движения.
Основное назначение отчета — очень быстро найти и показать места разницы в оборотах. Он не должен быть единственным инструментам контроля. Хотя бы потому, что не контролирует замену аналитики в проводках. Если в одной из баз кривые итоги, отчет все равно покажет расхождения, но для определения первопричины итоги нужно будет пересчитать.
Ну вот, только губу раскатаешь:
{ВнешнийОтчет.КомпараторОборотов.МодульОбъекта(213)}: Поле объекта не обнаружено (СуммаОборотДт1)
Результат.Строки[0][Колонка.Имя + Суффикс] = Результат.Строки[0][Колонка.Имя + Суффикс] + Таблица[0][Колонка.Имя]
Комплексная автоматизация, редакция 1.1 (1.1.50.1)
1С:Предприятие 8.2 (8.2.19.106)
(25) gull22, у меня эта ошибка не воспроизводится. Попробуйте на форме перевыбрать сравниваемый регистр — похоже, не обновился список сравниваемых показателей. А сравниваемые базы данных имеют одинаковые конфигурации?
Наверное настройки неправильно делал, подошел более вдумчиво, все получилось. Спасибо за труды
А Бухгалтерия предприятия 3.0 и УТ 10.3 можно будет через нее сравнивать?
(28) JuliettT, нет, нельзя. Сравниваются только конфигурации, имеющие одинаковые регистры. По измерениям и ресурсам. Кажется, таких регистров в БП 3.0 и УТ нет.
То есть обработке всегда нужно знать, что с чем сравнивать. Когда конфигурации совпадают или близки, то этот вопрос решается сам собой: сравниваются одноименные регистры, измерения и ресурсы.
А если конфигурации разные, то нужно еще придумать, как задать соответствие объектов для сравнения.
1. не верно распознает параметры подключения к 8.3
2. для серверных баз имя сервера не корректно вместо myServ заполняет Srvr=»myServ «;
3. имя базы в лишних кавычках
4. нет события при ошибки COM соединения
5. ошибки типа — Поле объекта не обнаружено (СуммаОборотДт1)
дальше пока не дошел
(30) vde69, спасибо, обратной связи по этой обработке не было, а она нужна. Ошибки буду поправлять. Сам этой обработкой пользуюсь довольно часто, считаю ее очень эффективной из-за заложенных принципов. Есть версия под УФ, но большого интереса не увидел и поэтому выкладывать пока не стал. Обход ошибки 5 — перевыбор регистра в поле формы.
(31), можете для 3.0 выложить? )
Там у вас ошибочка при сборке запроса. Который вы гоняите в процедуре Дихотомия. Посмотрите условия:
ГДЕ Период МЕЖДУ &От И &До И Организация = &Организация И (СчетДт В (&СчетаУчета))…
При таких условиях берется период не в заданных значения, а за всю историю регистра.
Так и не понял — как вы передаете в Результат значения регистраторов?
Хотел переделать, чтобы в качестве сравнения использовался xml файл из базы. Нужно когда не могу подключить базы, разные платформы и т.п. При переходе с 82 на 83 например.
(33) flex81,
При таких условиях берется период не в заданных значения, а за всю историю регистра.
Этого не понял. Условие
как раз и служит для ограничения области поиска значениями «От» и «До», которые все время сужаются (рекурсивно), что приводит к нахождению минимального интервала, содержащего расхождения.
(34) Кажется, что данную обработку взять за основу сравнения через xml будет не удобно. Все же она основана на серии уточняющихся запросов к двум «живым» базам. Если одна база в оффлайн, то то, что получается из итогов регистра (обороты на анализируемом интервале) придется эмулировать, выгрузив все движения, хотя … попробуйте.
Интересная вещь — попробую!
Отчет — шедевр! Отличный код и эффективность. Автору респект и уважуха!! 🙂 Применил для сверки бух.счетов при переходе с УПП на ERP (имя регистра бухгалтерии, измерений и ресурсов совпали), плюс немного доработал для соответствия документов и добавил сравнение по счетам проводок.
Отчет хороший, помогает найти расхождения. Подскажите, как можно добавить конкретные проводки под уровень с регистратором?
Т.е. отчет выводит регистратор и показывает итоговые суммы, а как можно выводить различия в проводках этого регистратора?
Доброго времени суток! Есть ли возможность сравнения в базах УТ и Бухгалтерия?
(39) Возможность то есть, но … сравнение ведется по регистрам одинакового наименования и одинаковой структуры, и, так как таких регистров, наверное, немного, то использование этого режима весьма ограничено.
Можно легко доработать на конкретный случай. Многие, судя по всему, это уже делали.
Когда я разрабатывал эту вещь, не придумал удобного и наглядного интерфейса для сопоставления сравниваемых регистров, поэтому и не стал делать обработку еще более универсальной.
(31) Да, очень нужен отчёт под 3.0 (УФ). Можно выслать на jdo1962@yandx.ru. (Плюс поставил)
(41) В данный момент отчета под 3.0 у меня нет. Попробую поискать или сделать заново, но быстро не обещаю.
(42) Спасибо за быструю реакцию. Кинь мне, пожалуйста, на почту jdo1962@yandex.ru последнюю версию. Я тут немного «поколдую» и тебе верну. Хороший труд, пусть стармани тебе капают, ты молодец.
(41) сделал пользователя, сказал ему запускаться под обычными формами и все ок. Отчет работает.
А подскажите откуда берется сумма во второй строчке итога?
https://snag.gy/TEOGsz.jpg
И неплохо было да расскрасить строчки 2 через 2, чтобы было понятно что с чем сравнивается.
А так работает. Расхождение нашел. Спасибо!
добрый день, на Бухгалтерии 8.2 в файловом режиме ошибка при запуске формирования отчета:
{ВнешнийОтчет.КомпараторОборотов.МодульОбъекта(191)}: Значение не является значением объектного типа (NewObject)
Query = COMObject.NewObject(«Query»);
При попытке подключения к информационной базе произошла ошибка:
Ошибка при вызове конструктора (COMОбъект): -2147221005(0x800401F3): Недопустимая строка с указанием класса
На вкладке Настройки подключения заполнены поля каталога ИБ для подключения и админ + пароль.
Что-то нужно дополнительно указать для подключения к ИБ?
(46) Тут, скорее, вопрос к вашему сисадмину, чтобы он COM-компоненту правильно зарегистрировал. С этим бывают проблемы после переустановки 1С.
ок, спасибо, соединение установлено. Теперь процесс сравнения завершается вот такой ошибкой: {ВнешнийОтчет.КомпараторОборотов.МодульОбъекта(213)}: Поле объекта не обнаружено (СуммаОборотДт1)
Результат.Строки[0][Колонка.Имя + Суффикс] = Результат.Строки[0][Колонка.Имя + Суффикс] + Таблица[0][Колонка.Имя]
(48) Тут, возможно, уже моя недоработка. Обычно помогает перевыбор регистра сравнения или изменение других полей формы. Тогда заново заполняются имена колонок таблицы формы, куда должны помещаться результаты сравнения.
(49) да, точно, перевыбор условий сравнения помог, все работает, спасибо. Скорость процесса действительно впечатляет — год за чуть больше минуты просканировал.