<?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). Да, точно красивее:) Спасибо!
(2) Интересная задумка
(3) СохранитьЗначение(<Имя>, <Значение>) , ВосстановитьЗначение(<Имя>) только для толстого клиента.
Лучше использовать ХранилищеОбщихНастроек.Сохранить, Загрузить, Удалить
(6) Пока не пробовал. В качестве минуса наверное можно выделить то, что эти настройки засоряют базу, т.к. при удалении обработки данные там остаются.
(7) Да все верно, поэтому нужно вызывать Удалить, или сразу после загрузки, или перед завершением сеанса через функцию ХранилищеОбщихНастроек.ПолучитьСписок(…) очищаем все настройки
Это однопользовательский вариант? Так имя параметра быстрее всего одинаковое для документов одного вида, то коллизии будут возникать с вероятностью чуть менее, чем полностью 🙂
(9) Хм, а ведь и правда, в случае, если два пользователя решат одновременно заполнить два разных документа, то коллизия неизбежна. По идее тут нужно еще одно измерение создавать, которое будет отвечать за уникальность значения данного параметра. Подумаю на эту тему, спасибо.
(10) достаточно ссылки на документ (?)
(8), с хранилищем общих настроек хорошая идея, но они же вроде сохраняются для определенного пользователя? В таком случае, как узнать в фоновом задании настройки какого пользователя читать?
(11) В общем случае ссылки на документ будет достаточно, ну или как вариант уникального идентификатора, чтобы не привязываться к типу объекта. Однако, в моем случае в процедуре, в которую нужно было передать дополнительный параметр не было ссылки на заполняемый объект, поэтому тут и могут возникнуть сложности в определении значения параметра
В общем случае метод годится только для случая, когда им пользуется только один сеанс. То есть не годится даже для регламентных заданий ;)) ИД сеанса нужно в измерения добавлять, как минимум. И передавать этот ИД в фоновое задание стандартным способом. Выигрыш только в том, что можно одним параметром передать сразу много, но что мешает передать структуру сразу ?
Вобсчем поржал. Спасибо.
(10)
(9)
Не будут, тк. хранилище работает, если не указывать конкретного пользователя, для каждого пользователяотдельно!
(16) а разве в публикации говорилось о хранилище?!
Не морочьте людям голову
(13)
Почему проблемы?
Параметр по этому ключу в РС. И фоновое задание запускать с этим ключом.
Относительно фоновых заданий хранилище имеет только обратную связь, т.е.
при запуске фонового задания в него можно передать адрес хранилища и после завершения фонового задания в точке его
запуска получить значения из хранилища.
Прямая связь не работает, т.е. поместить в хранилище значение, передать в фоновое адрес и в задании получить значение по этому адресу невозможно.
Именно поэтому возникают задачи как в (0)
Я считаю, что с броским названием тс перегнул, ибо
создать регистр хранения в конфигурации — это банальное решение в лоб не претендующее на рациональную идею и альтернативу. это костыль
Ну, можно поизвращаться.
На клиентском компутере:
1. Получаем новый УИД.
2. Блокируем по нему исключительно запись в РС.
3. Запускаем фоновое задание, в которое передаем-таки этот уид (только в функцию самого задания).
4. В бесконечном цикле (можно с паузой) опрашиваем фоновое задание на предмет сообщений пользователю.
5. Как только появляется сообщение в РС фигачим по номеру в этом собщении необходимый параметр и снимаем блокировку с записи РС из п.2.
В функции ФЗ:
1. Получаем номер сеанса.
2. Создаем сообщение пользователю, в которое добавляем этот номер сеанса.
3. Делаем запрос к РС по УИДу преданному в качестве параметра ФЗ.
4. Ждем на блокировке…
5. Выполняем свой код. В функции, где нужен параметр с клиента обращаемся в РС по НомерСеансаИнформационнойБазы().
6. Профит
PS Ну, и не забываем, где надо, транзакции всунуть, чтоб блокировка отработала.
PPS Но лучше, каеш, параметр протолкнуть по функциям 🙂
чтобы не изобретать велосипед советую использовать БСП
ДлительныеОперации.ЗапуститьВыполнениеВФоне()
(12) Воттут и тут я как раз этим и пользуюсь 🙂
Добрый день!
Немного поздновато, но всё же.
У меня архиватор баз, где все необходимые процедуры выполняется в фоне для одного «робота», а другие пользователи просто читаю что-то.
Вот «пухнет» база, я так понял что постоянная перезапись данных идёт.
Сделано через хранилище данных. Весь результат «робот» складывает в хранилище, к нему все подключаются и читают данные, которые отображаются на главной форме любого пользователя (ЗначениеВДанныеФормы()) с определённой для клиента периодичностью. Тут получается что нет никаких справочников, регистров и т.п.
Можно сделать через параметры сеанса, где данные тоже в виде хранилища. Вот данные хранилища будет оценивать «робот» и «распихивать» по таблицам (справочники, регистры). А у других пользователей на форму просто будет выведены стандартные динамические списки.
Кто сталкивался? Как правильнее сделать? Главный вопрос, на который я не нашёл ответа — при перезаписи хранилища каким образом данные заносятся в ТЧ СУБД. К примеру, старое хранилище с ТЧ помечается не актуальным, а новая информация ДОПИСЫВАЕТСЯ. Или в то же физическое пространство перезаписывается информация?