<?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='\
Мне кажется, что правильнее говорить не о версионировании, а о записи в ЖР информации об измененных значениях реквизитов.
(1) Идальго, да, согласен с вами, версионированием это можно назвать с очень большой натяжкой, нулевая точка отсчета для последующей возможной его реализации.
Еще один возможный минус такой записи изменений. Поскольку порядок выполнения однотипных подписок на событие не определен, вполне возможно, что после записи в журнал регистрации изменения объекта, следующая подписка на событие ПередЗаписью вызовет Отказ и объект не запишется. А в журнал регистрации уже попала запись об изменении объекта. То, что это «ложное срабатывание», можно будет определить только наличием после события об изменении реквизитов объекта события об отмене транзакции…
В моем варианте версионирования:
Показать
Запоминается состояние документа в событии «ПередЗаписью», потом в событии «ПриЗаписи» (если не было отказов) сравниваются реквизиты и ТЧ целиком. Создается запись в специальном регистре сведений, туда записывается сам факт действия и все измененные реквизиты и ТЧ, упакованные в один пакет с максимальным сжатием. Потом можно сформировать как глобальный отчет по изменениям, так и по конкретному документу посмотреть/сравнить/откатить.
(0) Сомнительное решение, по-моему. Журнал регистрации распухает очень быстрыми темпами в любой активно использующейся базе. А тут еще в него будут записываться довольно объемные записи. Причем, если такой механизм прикручен ко многим объектам, и их активно изменяют — таких записей будет много. В результате штатными средствами с Ж.Р. будет еще хуже работать.
Может быть, если Ж.Р переделан на хранение во внешней SQL-базе — есть публикация на Инфостарте об этом — будет нормально работать.
(4) maljaev, спасибо, интересно посмотреть другие варианты.
(5) kapustinag, регистрация изменений установлена только на критичные объекты — на несколько ключевых справочников и на все товаросодержащие документы, поэтому пока существенного увеличения ЖР не ожидаем. За наводку на SQL-ный журнал спасибо, мысль хорошая, подумаю.
Скорее наоборот. Значение реквизитов Источника это то, что будет после принятия изменений. По ссылке мы обращаемся к записям БД, которые как раз и есть значениями до изменения
Вместо журнала используйте регистр сведений, который можно периодически чистить. Отчет по записям регистра будет строиться несоизмеримо быстрее, чем анализировать записи журнала регистрации. Тем более, что подчищать регистр сведений опять таки проще.
(8) karapuzzzz, спасибо, посмотрю, может и правда перемудрил.
(9) karapuzzzz, ставилась цель без особых механизмов сделать простой инструмент для того, чтобы пользователь мог просматривать изменения документа. Поэтому решили по максимуму использовать штатные средства. Как я уже написал в (5), изменения регистрируются у нескольких справочников и документов, поэтому распухание ЖР скорее всего не грозит.
(5) kapustinag, не эту ли публикацию вы имели ввиду?Журнал регистрации изменений во внешней информационной базе 1С (MS SQL) (управляемые и обычные формы, демо-сервер)
Не, это дороговато…
во первых решение действительно «сомнительное», по тому как в реквизитах «ссылки» а не строки и там «моментов» много
во вторых банально туповато сделано в цикле….
я например вот так сделал (тут то же есть спорные моменты, но куда лучше чем дергать каждый реквизит отдельно):
Показать
(13) vde69, спасибо за уточнение, посмотрю. Пользователю, правда, на форме доступны именно те реквизиты, которые могут на что-то повлиять, остальные можно не трогать. А Полные права всегда что-то меняют под флагом ОбменДанными.Загрузка = Истина, поэтому их изменения не регистрируются.
(11) Если отбросить проблему распухания журнала регистрации, то остается еще 3:
1. Формирование отчета. Можно просмотреть информацию по документу из ЖР, но сформировать отчет можно быстрее. Даже не так. НАМНОГО БЫСТРЕЕ. Отчет предоставить больше данных. Это и отбор по периоду документа (ЖР такого не даст), и удобочитаемая форма, и представление ссылок как ссылок с возможностью открыть элемент справочника (например, если наименование у двух элементов одинаковое).
2. Разделение доступа. Человек, анализирующий записи может не иметь доступа на чтение ЖР и наоборот — человек, имеющий доступ к ЖР не должен иметь доступа к протоколу изменений (там же конкретные данные документов)
3. Очистка данных. Если использовать ЖР, то вместе с чисткой протокола изменений будет очищен и журнал. И наоборот.
(15) karapuzzzz, у нас была задача максимальной простоты реализации и максимального удобства для пользователя с минимумом выводимой информации.
Кто сидел на моем стуле и сломал его? (анализ изменений документа по журналу регистрации) . При выборе документа автоматически ставится период с даты документа по текущую дату, в общем случае этого достаточно, период при желании можно изменить.
Поэтому
1. Пользуемся вариантом обработки
2. В журнал регистрации никто не смотрит, т.к. большинство не умеют пользоваться отборами, работы хватает, не до этого и т.д.
3. Сейчас мы наоборот, на этапе накопления информации, вопрос пока не стоит.
В нашу специфику описанный метод вписывается вполне, осталось только сделать нормальный анализ таблиц.
(16) специфика журнала регистрации предполагает выборку всех данных, а потом ее анализ. Отбор можно установить только на конкретный документ, на пользователя, на период записей в журнале. Это и все, если не считать еще несколько отборов не нужных пользователям. Остальные отборы только на уже готовую выборку. А это время. Это очень большая нагрузка на систему.
Вы сейчас идете по принципу «система маленькая, нам хватает, развиваться не будем». Придет время рвать волосы и думать — чего раньше не сделали по уму. Я пытаюсь дать Вам понять, что реализация версионирования (протоколирования и т.п.) с использованием журнала регистрации это очень плохая идея. Многие настраивают перечень действий, вносимых в журнал регистрации, чтобы данных было минимум. Время от времени выгружают журнал и архивируют, оставляя только некий последний период. Все механизмы в системе стараются для ведения своего лога использовать свои таблицы, а не общую песочницу.
Если Вы уже добавили подписку на событие и процедуру в одном из общих модулей, что мешает добавить регистр сведений? Подумайте о своих коллегах, которым после Вас поддерживать продукт и анализировать, почему база пухнет. Простой анализ дает понять, что ссылка занимает меньше места, чем представление ссылки, а каждая запись журнала регистрации помимо осмысленных данных хранит еще кучу системной информации о клиенте, подключении и т.п. Строить правильную систему надо сначала, когда база это позволяет.
(17) karapuzzzz, я с вами ни в коей мере не спорю, коллега, а только обрисовываю ситуацию какая у нас сейчас.
Да, согласен, что в скором времени надо реализовывать более быстрый и оптимальный механизм.
Если резюмировать ваши комментарии, и комментарии коллеги в (4) и (13) надо реализовать примерно следующее:
1. В обработчике ПередЗаписью запомнить разницу между объектом и ссылкой, причем просматривать только необходимые реквизиты.
2. В обработчике ПриЗаписи, если не Отказ, окончательно записать изменения в свой созданный регистр сведений, желательно в реквизит типа ХранилищеЗначения чтобы иметь возможность упаковки с максимальной степенью сжатия:
3. Затем обработкой/отчетом извлекать полученные данные, конвертируя их в удобочитаемый вид.
Так что есть над чем поработать, и спасибо всем за ценную информацию, это пригодится не только мне.
(18) Есть ещё несколько соображений по поводу протоколирования:
1) Далеко не всегда известен объект анализа! Например, часто требуется найти все Документы в которых изменено количество некоторого Товара… Соответственно, изменяется Табличная Часть документа, реквизит Количество, а поиск удобнее организовать по ссылке Номенклатуры. При сворачивании Таблицы изменений — поиск по дополнительным признакам резко осложняется.
2) Штатное сравнение Табличных частей будет реагировать на изменение порядка строк в ТЧ! Частным случаем для накладных окажется изменение Единицы измерения с соответствующим пересчетом реквизита Количество…
Для борьбы с первой проблемой — указывал в ЖР ссылку Номенклатуры (вместо изменяемого документа), при сохранении ВидаМетаданных
Для борьбы со второй проблемой — особая ветка анализа ТЧ «Товары». Сравнивались Свернутые по измерениям (Номенклатура, Характеристика, Серия, Качество и т.п.) и приведенное к Единицам хранения количество… одновременно отбрасывались неактуальные реквизиты строк.
(19) V.Nikonov, да, предложенная в статье методика, что называется «просто и быстро», нулевой вариант. Отчета с отборами не получишь, а только фактическую информацию об изменениях всего чего можно. Изменения порядка строк в табличных частях выдадут большое количество изменений, среди которых нужное не найдешь и т.д.
Сейчас работаю над тем, чтобы этот вариант работал более-менее корректно с табличными частями. А там и до регистра сведений с настройками реквизитов вообще и табличных частей в частности доберемся.
За дельные советы спасибо)
Успешное использование механизма: менеджер случайно изменила в существующей позиции номенклатуры часть реквизитов — восстановили оригинал обратно в короткие сроки.
(4) maljaev, внедрил доп.контроль при записи, как у вас.
Обнаружил такую штуку.
Если отказ происходит в обработчике проведения (например, не заполнено количество), документ не записывается, но запись об изменении реквизитов все равно попадает в журнал регистрации (у вас — в механизм версионирования).
Делать дополнительную подписку на событие ПриПроведении тоже смысла нет, т.к. порядок подписок не определен.
Так что стопроцентного доп.контроля для документов, видимо, не сделать.
А для справочников годится.