Компаратор оборотов в информационных базах




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

50 Comments

  1. ardn

    Прикольно!

    Возможно стоит добавить еще детализацию показателей по измерениям, например номенклатура или склад. Поясню: в документе заменили одну позицию номенклатуры другой с той же ценой, сумма не поменялась. Изменили склад — сумма также не изменилась.

    А вообще — отлично!

    Reply
  2. ildarovich

    Забыл сказать, что на мысль использовать данный подход для сравнения движений документов в двух базах меня натолкнула статья Сравнение двух строк. Функция. А то, что метод дихотомии является популярным методом поиска ошибок, подтверждается, например, в статье Теория поиска ошибок 🙂.

    Reply
  3. ildarovich

    (1) ardn, это хорошее предложение — сделать настраиваемый фильтр по всем измерениям анализируемого регистра. — Подумаю над этим.

    Reply
  4. FractonKireyev

    Идея шикарная. Автору — мои аплодисменты.

    Но в методике по описанию сразу сразу несколько проблемных моментов:

    1. Интервал сравнения оборотов — 1 месяц. Документ перенесён с 10-го числа на 20-е. При сравнении оборотов за 1 месяц ничего не произошло (документ не поменял период сравнения оборотов). Но другой документ за 5-е число поменял обороты.

    При этом в пределах месяца получаем одну ошибку (на 1 копейку от документа за 5-е число), а при поиске этого документа делим интервал пополам и в каждом интервале получаем ошибку на много тысяч (от перенесённого документа). А если нет документа с изменёнными оборотами за 5-е число — то перенос документа с 10-го на 20-е вообще никак не обнаруживается.

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

    Reply
  5. JesteR

    «На фиг 1» интересно пишется )))

    Reply
  6. ildarovich

    (5) Так и было задумано.

    Reply
  7. ildarovich

    (4) По порядку

    1) Отчет показывает все эти изменения в достаточно понятном виде. В демо-базе БП в феврале 2009 оказались как раз документы в этих датах и были внесены указанные изменения. Вот, что показал отчет. Все вроде бы логично и проблемы не видно.



    2) Здесь Вы путаете с методом поиска экстремума функции, где «замер» показывает не наличие-отсутствие искомого объекта на интервале поиска, а значения функции (их нужно два), которые затем сравниваются, чтобы было понятно с какой стороны экстремум и куда идти. А бинарный поиск — это немного другое. Да просто попробуйте сыграть в «угадай число» с ответами «больше-меньше» и самая эффективная стратегия родится сама собой.

    Reply
  8. MadMix

    (4) FractonKireyev,

    1) Здесь сравниваются итоги, поэтому можно придумать много подобных ситуаций. Например, отличающиеся реквизиты в движениях или изменение суммы документа и ввод сторнирующих эти изменения проводок в том же месяце. Достоверность принесена в жертву скорости работы.

    Если нужно полное сравнение движений, проще выгрузить движения в табличный документ в одинаковом виде и сравнить через «сравнение файлов» или любую другую DIFF-программу.

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

    UPD: внутри месяца будет быстрее сразу сравнивать таблицы движений, так как они все равно будут использоваться при расчете остатков на произвольную дату внутри месяца.

    Reply
  9. ildarovich

    (8) MadMix,

    1) Все так, но я бы сказал, что в жертву скорости работы принесена не достоверность, а полнота контроля. Полноту можно увеличить, если контролировать итоги, развернутые по измерениям.

    2) Метод золотого сечения здесь совершенно не причем. Значения функции в нем вычисляются для поиска точки, в которой функция достигает максимума (или минимума). Как это связать со сравнением оборотов? Предлагаете искать максимум или минимум чего?

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

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

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

    Reply
  10. MadMix

    (9) здесь функцию можно представить как дискретную функцию:

    f(x) = 1, когда есть отличия между оборотами в базах за период от НачалоПериода до НачалоПериода + x;

    иначе f(x) = 0.

    Поэтому вполне можно применять любые методы поиска экстремума.

    Reply
  11. ildarovich

    (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).

    Reply
  12. MadMix

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

    В вашем же примере — при дихотомии нужно будет вычислить значение функции 19 раз (по 2 раза на каждой итерации и 1 раз на первом шаге). При использовании золотого сечения — только 15 раз.

    Проблема с поиском всех отличий тоже решается достаточно просто.

    Reply
  13. ildarovich

    (12) MadMix, давайте разжевывать до конца…

    Если функция унимодальна (отличие только одно), то при дихотомии на одной итерации потребуется ОДНО вычисление функции — делим интервал надвое и проверяем (сравниваем обороты) правый интервал: если отличие есть, выбираем в качестве следующего его, иначе — берем левый интервал. Так что вычислений функции — 10.

    И про это

    Проблема с поиском всех отличий тоже решается достаточно просто

    тоже поподробнее, пожалуйста.

    Reply
  14. ildarovich

    (12) Ну и вообще, чтобы спор не был голословным, может быть предложите свою функцию для сравнения двух строк методом золотого сечения? Это простая задача из статьи http://infostart.ru/public/174530/. Можно будет сравнить быстродействие не на словах, а на деле. В комментарии http://forum.infostart.ru/forum24/topic80332/message852380/#message852380 есть обработка, куда сможете вложить свою функцию. Мне кажется, при попытке применить золотое сечение к этой задаче на практике, сразу станет ясно «той ли системы ваши гранаты».

    Reply
  15. Makushimo

    Жееесть -))

    Ребята, ваш спор — это жесть ;-))

    Reply
  16. agrustny

    (15) Нормальный спор, мягкий вполне себе. Только студента куда-то след простыл, когда его попросили показать домашнее задание…

    Reply
  17. artbear

    (0) Хорошая обработка, давным-давно я также делал аналогичную работу (есть в профиле).

    Но у тебя ИМХО намного мощнее, лучше и удобнее получилось.

    Молодец.

    Спасибо!

    Reply
  18. ildarovich
  19. ildarovich

    Появилась еще одна обработка для решения той же задачи: Сравнение оборотно-сальдовой ведомости двух баз и поиск различий в операциях (проводках документов). Разница в том, что там сначала строится ОСВ, а потом находятся различия путем последовательного сравнения проводок по счету. Минус такого подхода — в бОльших затратах времени, а плюс — в том, что используемые формы отчетов имеют привычный вид. Также там упоминается обработка, взятая за основу: http://infostart.ru/public/167127/.

    Предлагаемая здесь обработка фактически работает не со всей ОСВ, а с ее последней итоговой строчкой (хотя можно отбирать счета и показатели). Поэтому идеальная обработка все же должна быть разделена: первая должна сравнивать обороты за весь период в развороте по всем счетам и измерениям, а вторая — дихотомией находить собственно причины расхождений по ранее определенным измерениям. Иначе можно не заметить изменения аналитики в проводках.



    В коллекцию ссылок еще отчет по той же теме: Сравнение регистров бухгалтерии с копией базы для БП 2.0 на платформе 8.2.

    Reply
  20. Rustig

    (0) да, это тоже сильно! отличная статья

    Reply
  21. Dach

    Ваш отчет на регистрах накопления в ЗУП 2.5 не работает. Скрин ошибки http://itmages.ru/image/view/1843779/69e9f753

    Reply
  22. ildarovich

    (21) Dach, все работает и дело не в конфигурации. Этот отчет принципиально требует заданного интервала анализа, а вы его не задали — отчету нечего делить пополам, вот он и вылетает. Нужно будет вставить проверку на непустые значения!

    Reply
  23. Dach

    (22) ясно… в недрах отчета не ковырялся, скажите, он сравнивает результаты, хранящиеся в виртуальных таблицах остатков и оборотов или сам агрегирует суммы? Потому что в ситуации, когда в одной из баз кривые итоги… далее можно не продолжать….

    Reply
  24. ildarovich

    (23) Dach, отчет работает с виртуальными регистрами, а они уже агрегируют суммы. Внутри интервалов хранения итогов (месяц) работа с виртуальными регистрами будет опираться не только на сами итоги, но и на движения.

    Основное назначение отчета — очень быстро найти и показать места разницы в оборотах. Он не должен быть единственным инструментам контроля. Хотя бы потому, что не контролирует замену аналитики в проводках. Если в одной из баз кривые итоги, отчет все равно покажет расхождения, но для определения первопричины итоги нужно будет пересчитать.

    Reply
  25. gull22

    Ну вот, только губу раскатаешь:

    {ВнешнийОтчет.КомпараторОборотов.МодульОбъекта(213)}: Поле объекта не обнаружено (СуммаОборотДт1)

    Результат.Строки[0][Колонка.Имя + Суффикс] = Результат.Строки[0][Колонка.Имя + Суффикс] + Таблица[0][Колонка.Имя]

    Комплексная автоматизация, редакция 1.1 (1.1.50.1)

    1С:Предприятие 8.2 (8.2.19.106)

    Reply
  26. ildarovich

    (25) gull22, у меня эта ошибка не воспроизводится. Попробуйте на форме перевыбрать сравниваемый регистр — похоже, не обновился список сравниваемых показателей. А сравниваемые базы данных имеют одинаковые конфигурации?

    Reply
  27. gull22

    Наверное настройки неправильно делал, подошел более вдумчиво, все получилось. Спасибо за труды

    Reply
  28. JuliettT

    А Бухгалтерия предприятия 3.0 и УТ 10.3 можно будет через нее сравнивать?

    Reply
  29. ildarovich

    (28) JuliettT, нет, нельзя. Сравниваются только конфигурации, имеющие одинаковые регистры. По измерениям и ресурсам. Кажется, таких регистров в БП 3.0 и УТ нет.

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

    А если конфигурации разные, то нужно еще придумать, как задать соответствие объектов для сравнения.

    Reply
  30. vde69

    1. не верно распознает параметры подключения к 8.3

    2. для серверных баз имя сервера не корректно вместо myServ заполняет Srvr=»myServ «;

    3. имя базы в лишних кавычках

    4. нет события при ошибки COM соединения

    5. ошибки типа — Поле объекта не обнаружено (СуммаОборотДт1)

    дальше пока не дошел

    Reply
  31. ildarovich

    (30) vde69, спасибо, обратной связи по этой обработке не было, а она нужна. Ошибки буду поправлять. Сам этой обработкой пользуюсь довольно часто, считаю ее очень эффективной из-за заложенных принципов. Есть версия под УФ, но большого интереса не увидел и поэтому выкладывать пока не стал. Обход ошибки 5 — перевыбор регистра в поле формы.

    Reply
  32. serggo

    (31), можете для 3.0 выложить? )

    Reply
  33. flex81

    Там у вас ошибочка при сборке запроса. Который вы гоняите в процедуре Дихотомия. Посмотрите условия:

    ГДЕ Период МЕЖДУ &От И &До И Организация = &Организация И (СчетДт В (&СчетаУчета))…

    При таких условиях берется период не в заданных значения, а за всю историю регистра.

    Так и не понял — как вы передаете в Результат значения регистраторов?

    Reply
  34. flex81

    Хотел переделать, чтобы в качестве сравнения использовался xml файл из базы. Нужно когда не могу подключить базы, разные платформы и т.п. При переходе с 82 на 83 например.

    Reply
  35. ildarovich

    (33) flex81,

    ГДЕ Период МЕЖДУ &От И &До И Организация = &Организация И (СчетДт В (&СчетаУчета))…

    При таких условиях берется период не в заданных значения, а за всю историю регистра.

    Этого не понял. Условие

    Период МЕЖДУ &От И &До

    как раз и служит для ограничения области поиска значениями «От» и «До», которые все время сужаются (рекурсивно), что приводит к нахождению минимального интервала, содержащего расхождения.

    (34) Кажется, что данную обработку взять за основу сравнения через xml будет не удобно. Все же она основана на серии уточняющихся запросов к двум «живым» базам. Если одна база в оффлайн, то то, что получается из итогов регистра (обороты на анализируемом интервале) придется эмулировать, выгрузив все движения, хотя … попробуйте.

    Reply
  36. vis_tmp

    Интересная вещь — попробую!

    Reply
  37. snisni2

    Отчет — шедевр! Отличный код и эффективность. Автору респект и уважуха!! 🙂 Применил для сверки бух.счетов при переходе с УПП на ERP (имя регистра бухгалтерии, измерений и ресурсов совпали), плюс немного доработал для соответствия документов и добавил сравнение по счетам проводок.

    Reply
  38. XOCTEP

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

    Т.е. отчет выводит регистратор и показывает итоговые суммы, а как можно выводить различия в проводках этого регистратора?

    Reply
  39. dj_casanova

    Доброго времени суток! Есть ли возможность сравнения в базах УТ и Бухгалтерия?

    Reply
  40. ildarovich

    (39) Возможность то есть, но … сравнение ведется по регистрам одинакового наименования и одинаковой структуры, и, так как таких регистров, наверное, немного, то использование этого режима весьма ограничено.

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

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

    Reply
  41. jdo

    (31) Да, очень нужен отчёт под 3.0 (УФ). Можно выслать на jdo1962@yandx.ru. (Плюс поставил)

    Reply
  42. ildarovich

    (41) В данный момент отчета под 3.0 у меня нет. Попробую поискать или сделать заново, но быстро не обещаю.

    Reply
  43. jdo

    (42) Спасибо за быструю реакцию. Кинь мне, пожалуйста, на почту jdo1962@yandex.ru последнюю версию. Я тут немного «поколдую» и тебе верну. Хороший труд, пусть стармани тебе капают, ты молодец.

    Reply
  44. Cartman

    (41) сделал пользователя, сказал ему запускаться под обычными формами и все ок. Отчет работает.

    Reply
  45. Cartman

    А подскажите откуда берется сумма во второй строчке итога?

    https://snag.gy/TEOGsz.jpg

    И неплохо было да расскрасить строчки 2 через 2, чтобы было понятно что с чем сравнивается.

    А так работает. Расхождение нашел. Спасибо!

    Reply
  46. Philosof

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

    {ВнешнийОтчет.КомпараторОборотов.МодульОбъекта(191)}: Значение не является значением объектного типа (NewObject)

    Query = COMObject.NewObject(«Query»);

    При попытке подключения к информационной базе произошла ошибка:

    Ошибка при вызове конструктора (COMОбъект): -2147221005(0x800401F3): Недопустимая строка с указанием класса

    На вкладке Настройки подключения заполнены поля каталога ИБ для подключения и админ + пароль.

    Что-то нужно дополнительно указать для подключения к ИБ?

    Reply
  47. ildarovich

    (46) Тут, скорее, вопрос к вашему сисадмину, чтобы он COM-компоненту правильно зарегистрировал. С этим бывают проблемы после переустановки 1С.

    Reply
  48. Philosof

    ок, спасибо, соединение установлено. Теперь процесс сравнения завершается вот такой ошибкой: {ВнешнийОтчет.КомпараторОборотов.МодульОбъекта(213)}: Поле объекта не обнаружено (СуммаОборотДт1)

    Результат.Строки[0][Колонка.Имя + Суффикс] = Результат.Строки[0][Колонка.Имя + Суффикс] + Таблица[0][Колонка.Имя]

    Reply
  49. ildarovich

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

    Reply
  50. Philosof

    (49) да, точно, перевыбор условий сравнения помог, все работает, спасибо. Скорость процесса действительно впечатляет — год за чуть больше минуты просканировал.

    Reply

Leave a Comment

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