Сравнение элементов справочников двух баз по COM соединению. Теперь на управляемых формах.




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

37 Comments

  1. OBEH

    «Идентичность» — Это код и наименование в справочниках разных конф?

    Reply
  2. ediks

    (1)Я вроде написал, что сравнение идет по выбранным реквизитам. Кнопка «Настройка» открывает форму выбора реквизитов.

    Reply
  3. OBEH

    (2)Я еще не смотрел обработку. Просто вопрос возник.

    Если, например, по коду можно, то дело стоящее.

    А если, например, одна база на платформе 8.1, а другая база на платформе 8.2?

    И еще. Идея. Мне кажется, коль пошла такая пьянка, может быть стоит добавить

    на форму кнопку, которая формирует отчет по несовпадающим элементам?

    Reply
  4. ediks

    (3)

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

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

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

    Reply
  5. OBEH

    (4)Ну, так скоро и будет, переходы на «родственные» базы, но 8.1 на 8.2

    Я так думаю, к новому году все потянутся на 8.2

    Reply
  6. OBEH

    Поверил человеку. А тут, оказывается, с 8.2 не работает

    Reply
  7. OBEH

    Переконвертировал под 8.2. Вроде, заработало.

    Вот только шаг счетчика, наверное, надо бы на больших объемах ставить, например, 100

    А то тормозит очень на выводе строки счетчика. Неужели не встречался с такой пакостью ни разу?

    Reply
  8. OBEH

    Во! Рухнула задача по ошибке «Недостаточно памяти».

    Примерно, на 40 тысяче записи.

    И чего делать?

    Reply
  9. ediks

    (6) Насчет 8.2: я написал что нужно сделать на форме — добавить в список выбора строку 8.2. И ничего не нужно конвертировать — из под 8.1 прекрасно соединяется с 8.2.

    (7) Процесс вывода занимает сравнительно небольшое время по сравнению с поиском COM объектов. Но код открыт — все в твоих руках.

    (8) Попробуй уменьшить число сравниваемых реквизитов или задать фильтры в отборе. По умолчанию, сравнивается по всем реквизитам. Соответственно, если справочник содержит много реквизитов, то выборка получается очень большая. На 8 гигах оперативки при минимальном количестве сравниваемых реквизитов (1 — 😀 ) удавалось сравнить справочник договоров в 500-600 тыс. записей.

    Reply
  10. OBEH

    (9)У меня не получилось установить выбор на 8.2

    Там показывалось только 8.1(по умолчанию) и 8.0

    8.2, вообще, даже вручную, не проходит. Тем более «прекрасно» не соединяется с 8.2

    Процесс вывода можешь сам проверить, установив шаг, например, сто.

    Будешь удивлен.

    Количество сравниваемых реквизитов я сделал два — Код и Наименование.

    Меньше нет смысла, а больше не надо.

    По поводу того, что все в моих руках — конечно, могу код править,

    но, пока не вижу смысла большого

    Reply
  11. ediks

    (10) Добавлять в список выбора 8.2 нужно в режиме конфигуратора.

    Reply
  12. Virsy

    Выпала ошибка при сравнении реквизитов табличной части справочника:

    {ВнешняяОбработка.СравнениеСправочниковВРазныхБазах(32)}: Ошибка при установке значения атрибута контекста (Текст): {(41, 14)}: Поле не найдено «Справочники.НомерСтроки»

    Справочники.<<?>>НомерСтроки,

    Построитель.Текст = СформироватьТекстЗапроса(1, КоличествоВВыборке);

    по причине:

    {(41, 14)}: Поле не найдено «Справочники.НомерСтроки»

    Справочники.<<?>>НомерСтроки,

    Reply
  13. ediks

    (12) Табличные части не сравниваются. Это описано во встроенной справке.

    Reply
  14. Virsy

    (13) тогда неплохо бы их не добавлять в список реквизитов

    Reply
  15. ediks

    (14) Был такой глюк 😀 . Исправился. Спасибо за наводку.

    Reply
  16. Tokiy

    Ешчо один «глюк»: когда есть две табличные части, например «Образование» и «ДопОбразование», то в этом куске

    //

    // выкусим наименования табличных частей

    Для каждого ТабличнаяЧасть Из Метаданные.Справочники[ТипОбъекта].ТабличныеЧасти Цикл

    ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ТабличнаяЧасть.Имя + «.», «»);

    КонецЦикла;


    //

    в слове «ДопОбразование.» он обрезает «Образование.» и потом ругается на слово «Доп»:

    {(25, 14)}: Поле не найдено «Справочники.Доп»

    Справочники.<<?>>Доп

    Т.е. не совсем корректный подход к определению реквизитов. Почему бы просто не перебрать реквизиты метаданных?

    Reply
  17. Tokiy

    А вообще качал в надежде что обрабатывает табличные части..

    Reply
  18. v_id

    {ВнешняяОбработка.СравнениеСправочниковВРазныхБазах(583)}: Метод объекта не обнаружен (СообщитьИнформациюПользователю)

    ОбщегоНазначения.СообщитьИнформациюПользователю(«Количество записей внешней базы: » + Количество);

    8.1 Две УТ 10.3

    Reply
  19. ediks

    (16) Спасибо за наводку. Вроде исправил.

    Насчет корректности подхода: простой перебор реквизитов по метаданным не дает таких реквизитов, как Владелец, Родитель, Код, Наименование, Пометка удаления, Предопределенный и т.д. Соответственно, их наличие необходимо анализировать дополнительно. Мне показалось это несколько неудобным.

    Конструктор запроса делает этот анализ за меня, корректно выбирая все реквизиты.

    Reply
  20. ediks

    (18) Исправил этот глюк. Действительно, в УТ нет такой процедуры. Спасибо, что подсказали.

    Reply
  21. v_id

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

    Reply
  22. ediks

    (21) Добавил «цветовую дифференциацию штанов строк» 😀 , попросту говоря, раскраску. А вообще я сразу делаю отбор по реквизиту «Свертка», вывожу список и копирую отобранные коды в какую-нибудь обработку обмена.

    Reply
  23. powerpc

    А для сравнения документов можно сделать такую же обработку ? Особенно необходимо для сравнения выгрузки УТ в Бухгалтерию. Спасибо заранее

    Reply
  24. pantera190

    спасибо.пригодилось.

    Reply
  25. slav4ek

    спасибо)

    Reply
  26. bar_s

    спасибо.пригодилось.

    Reply
  27. RTA

    кто может дать на нее прямую ссылку?

    Reply
  28. rasswet

    обычная форма. где там закладка «расхождения»? или таковой нет?

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

    Reply
  29. ediks

    (28)

    1) В обычной форме нет закладки «Расхождения» — данные выводятся в табличной части ниже, под отбором.

    2) Каждая строка идентифицируется полем ГУИД и свертка. -1 означает, что объект находится во внешней базе. Соответственно, у Вас получается, что элементы справочника различаются, например, по полю ГУИД, если у них одинаковые код и наименование. Это возможно, например, если в базах элементы заводились вручную.

    В управляемой форме то же самое, но нет раскраски строк.

    Reply
  30. lees

    Спасибо! В хозяйстве пригодилось. Еще б была возможность сравнивать 8 с 7.7, тогда было б ваще круть.

    Reply
  31. www2007

    Спасибо, пригодилось, и времени сэкономило немало… Полезная вещь..

    Reply
  32. SkorikA

    Ошибочка:

    {ВнешняяОбработка.СравнениеСправочниковВРазныхБазах.МодульОбъекта(60)}: Ошибка при вызове метода контекста (Добавить)

    Построитель.Отбор.Добавить(«Владелец»,, «Владелец»);

    по причине:

    Недопустимое значение параметра (параметр номер ‘1’)

    Я так понимаю, если справочник подчинен владельцу и его не выбрал — то не работает?

    Reply
  33. ediks

    (33) Попробовал воспроизвести ошибку — не получилось. Не могли бы Вы подробнее описать условия возникновения ошибки: какая конфигурация, какой справочник, в какой момент возникает (при выборе типа объекта, при нажатии на кнопку «Настройка» и т.д.)?

    Reply
  34. Светлый ум

    {ВнешняяОбработка.СравнениеСправочниковВРазныхБазах.МодульОбъекта(577)}: Ошибка при установке значения атрибута контекста (Текст)

    КомПостроитель.Текст = СформироватьТекстЗапроса(-1, КоличествоВВыборке);

    по причине:

    Произошла исключительная ситуация (1C:Enterprise 8.2.19.121): {(18, 14)}: Поле не найдено «Справочники.ФактическийАдресУдалить»

    Справочники.<<?>>ФактическийАдресУдалить,

    Reply
  35. Светлый ум

    (35) Светлый ум,

    Ошибка возникала при работе с Розница 1.0 —> БП 2.0

    (сравнение справочника Контрагенты)

    Поправил текст процедуры и заработало:

    Функция СформироватьТекстЗапроса(пСвертка = 1, пКоличествоВВыборке = 0)
    
    Если НЕ ЗначениеЗаполнено(ТипОбъекта) Тогда Возврат «» КонецЕсли;
    
    УсловиеПоКоличеству = ?(пКоличествоВВыборке = 0, «», «ПЕРВЫЕ » + Формат(пКоличествоВВыборке, «ЧГ=0»));
    ТекстЗапроса =
    «ВЫБРАТЬ » + УсловиеПоКоличеству + »
    | » + пСвертка + » КАК Свертка,
    | Выразить(«»»» КАК Строка(36)) КАК ГУИД, Справочники.Ссылка КАК Ссылка, «;
    Для каждого СтрокаТЧ Из РеквизитыОбъекта Цикл
    
    Если Не Прав(СтрокаТЧ.Имя,7)= «Удалить»
    И Не СтрокаТЧ.Имя = «БанковскиеРеквизиты»
    И Не СтрокаТЧ.Имя = «ГруппаПолучателейСкидки»
    И Не СтрокаТЧ.Имя = «ПодписьДолжность»
    И Не СтрокаТЧ.Имя = «ПодписьФИО»
    И Не СтрокаТЧ.Имя = «ГоловнаяОрганизация»  Тогда
    
    Если СтрокаТЧ.Пометка Тогда
    ТекстЗапроса = ТекстЗапроса + »
    | Справочники.» + СтрокаТЧ.Имя + «,»;
    КонецЕсли;
    КонецЕсли;
    
    КонецЦикла;
    ТекстЗапроса = ЛЕВ(ТекстЗапроса, СтрДлина(ТекстЗапроса) — 1) + »
    |ИЗ
    | Справочник.» + ТипОбъекта + » КАК Справочники»;
    
    Возврат ТекстЗапроса;
    
    КонецФункции // СформироватьТекстЗапроса()
    

    Показать

    Reply
  36. Yran

    Скачал, попробовал запустить на БП 3.0 — выдала ошибку: Основная таблица динамического списка задана не верно. Не задан ни текст запроса, ни основная таблица динамического списка.

    При открытии зачем спрашивает?

    Reply
  37. ediks

    (37) Исправил, спасибо за информацию. Попробуйте скачать еще раз. Если возникнут проблемы, пишите, вышлю в личку.

    Reply

Leave a Comment

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