Поиск и удаление неиспользуемых элементов справочников




Принцип обмена данными из 1С с сайтом (на MySQL) и выдачи (публикации) этих данных по запросу.
PHP-Скрипт автоматической загрузки данных из файла данных в формате CSV в базу данных сайта работающего на WordPress.

В продолжение моей темы: 1С:Альфа-Авто Автосалон Автосервис: обмен с сайтом.
С помощью данного скрипта можно загружать в автоматическом режиме, по расписанию, данные сервисных книжек (ремонтов авто) из 1С:Альфа-Авто Автосалон Автосервис.
Также можно загружать данные в ручном режиме: для этого делается скрытая страница, где размещается специальная кнопка.
Комментарии размещенные внутри скрипта разъяснят логику и порядок действия.
Комментарии с "/////    echo" использовались для отладки.
Дополнительно создана таблица для журналирования результатов загрузки данных.
Скрипт включает в себя защиту от SQL инъекций (думаю безопасность соблюдена в полной мере).
В кратце:
1. Пишется скрипт, который запускает этот.
2. Создается регламентное задание в WordPress, по которому запускается скрипт из п.1. 
3. Этот скрипт осуществляет проверку на существование файла обмена в папке.
4. Если данные не новые, загрузка не производится.
5. Если данные новые, очищается таблица сервисных книжек.
6. Загружаются новые данные.

Собственно сам скрипт:

<?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='\

55 Comments

  1. sbv2005

    Проверено. Работает!

    Reply
  2. grGogy

    Про подчинённые справочники автор слукавил.

    Ссылка из подчинённого справочника определяет элемент в Используемые.

    Reply
  3. Lyekka

    Актуально. Спасибо.

    Reply
  4. defender

    (2) Нужно снять галочку «неиспользуемые без ссылок»

    Reply
  5. grGogy

    (4) Именно со снятой галочкой.

    Reply
  6. Tarlich

    Однозначно + (Только надо еще проверить в действии)

    Reply
  7. Tarlich

    Что ставлю , что не ставлю «Неиспользуемые без ссылок» — номенклатуру у которой есть ссылка только на ед.изм всеравно ставит как используемые -((

    Reply
  8. defender

    (5) (7) Сорри, была ошибка, исправил, перезалил.

    Спасибо

    Reply
  9. rasswet

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

    Reply
  10. defender

    (9) Покажет если это ведущее измерение

    Reply
  11. Abadonna

    Берешь справочник, помечаешь ВСЕ элементы на удаление.

    Делаешь стандартную «Удаление помеченных объектов»

    С оставшихся в живых пометки снимаешь.

    Вот и вся обработка, зато гарантия 100%, что ничего случайно не грохнешь

    Reply
  12. defender

    (11) 1. Этой обработкой тоже 100% ничего случайно не грохнешь.

    2. Элементы которые были помечены на удаление, после отмены пометки таковыми быть перестанут.

    Reply
  13. Abadonna
    Элементы которые были помечены на удаление, после отмены пометки таковыми быть перестанут.

    А и не фиг им быть помеченными, раз ссылки есть 😉

    Reply
  14. defender

    (13) Юзеры иногда помечают для каких-то там своих хитрых целей (как-то видел как девушка рабочие документы хранила в «корзине»). И не нужно трогать то, что не нами помечалось.

    Reply
  15. Abadonna

    Разбаловал ты своих юзверей 😉

    А у меня шаг влево — шаг вправо: уже на экзекуцию нарвался

    Reply
  16. johnrex

    Прекрасная разработка. Сам хотел уже писать, а тут уже всё оказывается написано до нас!

    Есть один серьезный изъян, но его исправить можно одной строчкой кода.

    Для подчиненных справочников это работать не будет:

    строкаТипа = Строка(ТипЗнч(Стр.Данные));

    Потому что для ссылки справочника строкаТипа станет, например «ЕдиницаИзмерения», а дальше по коду:

    ИначеЕсли Найти(строкаТипа, «Справочник») > 0

    Разумеется ничего найдено не будет и подчиненный справочник будет пропущен. Соответственно переменная должна принять значение вроде «СправочникСсылка.ЕдиницыИзменения»

    Можно сделать вот так:

    строкаТипа = Стр.Метаданные.ПолноеИмя();

    Reply
  17. xavi

    (16) Если применить это исправление, тогда в строке

    ИначеЕсли Найти(строкаТипа, «Регистр сведений») > 0 Тогда

    нужно убрать пробел:

    ИначеЕсли Найти(строкаТипа, «РегистрСведений») > 0 Тогда

    Reply
  18. kauksi

    РАБОТАЕТ! в отличие от многих других обработок!

    Reply
  19. provnick

    Интересно, в бухгалтерии заработало, а в УТ, по контрагентам работает, а по номенклатуре сработало только после изменений замеченных в (16) и (17), и не удаляет найденное, а только помечает, и так же в 8.2, соответственно после конвертации так же работает. И если возможно, желательно, не только наименование, но код, чтобы отображался.Плюс.

    Reply
  20. defender

    (16)(17)(19) Доработал поиск, сконвертировал под 8.2. Спасибо

    Reply
  21. kozai05

    Отлично, а а то у соседнего аналога почему-то не было в списке справочника «Контрагенты».

    Reply
  22. kozai05

    Проверил, выбрал справочник контрагентов. Убрал галочку «Неиспользуемые без ссылок». Обработка вывела мне все в используемые. Что-то не пойму, может это не то что мне нужно? У меня стоит цель очистить справочник от контрагентов, которые не участвую ни в каких остатках или оборотах. Но ведь у них хоть как будет ссылка с договора или регистра контактной информации, это в обработке предусмотрено? По какому принципу работает этот крыжик?

    Reply
  23. defender

    Если крыжик установлен — в неиспользуемые выбираются те у которых нет вообще никаких ссылок.

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

    задумывалось именно так.

    Reply
  24. kozai05

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

    Выходит примерно такая картина:

    http://s017.radikal.ru/i409/1110/b0/2a5b6914daad.jpg

    Reply
  25. yushmakovmv

    Полезная вещь.

    Reply
  26. Najly

    Ваша обработка очень помогла, спасибо большое. Но пришлось поправить три строчки:

    1) На условие Найти(строкаТипа, «РегистрСведений») > 0 РегистрыСведений не отлавливались, предполагаю, что там опечатка в какой-то из букв р,е,с,т,н. Переписала заново в русской раскладке, все заработало.

    2) Когда вы ищете по наименованию метаданных, тип на которой ссылается объект, рекомендую поставить в поисковой строке «.». То есть, например, Найти(строкаТипа, «Документ.») > 0, иначе под это условие подходит регистр сведений ОбъектыДоступаДокументов.

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

    ИначеЕсли Найти(строкаТипа, «Справочник.») > 0 Тогда

    Если Стр.Данные <> мО И НЕ Стр.Данные.ПометкаУдаления Тогда

    Reply
  27. Genneral

    Спасибо, Номенклатуру в УТ 10.3 после свертки почистила на ура.

    Reply
  28. yalo

    В справочнике Контрагентов был полный караууу. Спасибо все почистила, очень пригодилась!!!!!

    Reply
  29. izz

    Спасибо! Пользуюсь этой обработкой

    Reply
  30. lootinn

    Полезная обработка, после внесения изменений из (26) с контрагентами работает как надо.

    Reply
  31. NtS

    а у меня контрагентов все равно не чистит(((как будьто ссылка на самого контрагента

    Reply
  32. NtS

    (31) заработало!!! комментарии как следует нужно читать )) огромное спасибо (26)

    Reply
  33. defender

    (32) По многочисленным просьбам трудящихся 🙂 сделал доработки из (26)

    Reply
  34. OLga_gab

    Спасибо!!! Классно работает!

    Reply
  35. lees

    Мне интересна была реализация, пригодится потом. Спасибо!

    Reply
  36. infotrade

    Обработка полезна, после внесения некторых изменений все работает… Спасибо автору…

    Reply
  37. CaSH_2004

    (11)

    Берешь справочник, помечаешь ВСЕ элементы на удаление.

    Делаешь стандартную «Удаление помеченных объектов»

    С оставшихся в живых пометки снимаешь.

    Вот и вся обработка, зато гарантия 100%, что ничего случайно не грохнешь

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

    1. Предположим что в базе ОЧЕНЬ много элементов, пометка на удаление это получение объекта со всеми вытекающими, т.е. запись, а это соответственно ОЧЕНЬ долго, уверен что дольше чем просто сравнить какие ссылки и на что

    2. Далее даже если 1 не верно, то после пометки нужно делать тот же самый поиск ссылок и контроль уникальности — а это таже куча времени которое мы вроде должны съэкономить, потом удаление, а потом только опять снятие пометки удаления со ВСЕХ элементов. т.е. если у нас 100 тыс. из них скажем 10 тыс. неиспользуемых, то мы гоняем запись просто так 90 тыс элементов (с подчиненными!!!) аж 2 раза!!! только ради удаления 10% — за это просто уволить нужно человека

    3. Особый нюанс с подчиненными — они тоже удаляются и это арифметиеская прогрессия количества объектов

    4. А что делать если базу нельзя монопольно взять? Или будем удалять, а пользователи пусть работают как могут? Вот только они не смогут.

    5. Что интересно делать если в базе версионизация настроена? Куча дополнительных пустых записей что мы гоняли 90 тыс. объектов в состояния?

    6. Что делать если настроено хитрое реагирование на пометку удаления объекта, а мы не в курсе т.к. база не наша или просто забыли? А действия необротимые или сложно-обратимые

    7. Что делать если база РБД? Все объекты помеченные пойдут в обмен даже если их снять с пометки файл распухнет и все это будет грузиться, т.е. надо и это учитывать а если не учли? а филиалов несколько?

    Это основные проблемы РЕАЛЬНО с которыми я столкнулся, и на такой вариант проблемы я бы пошел только четко зная сколько примерный % неиспользуемых, как работает база, и что: нет РБД, версионизирования, она типовая

    Конечно это во многом решается ОбменДанными.Загрузка = Истина, однако запись то все равно идет, и не везде этот отсев отработает, только там где он проверяется.

    Вобщем я за ювелирный подход, не надо «отрезать палец по самое горло» 🙂 а то пациента это не обрадует

    Reply
  38. CaSH_2004

    (13)

    А и не фиг им быть помеченными, раз ссылки есть

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

    Reply
  39. defender

    (37) CaSH_2004,

    мощно задвинул, зачот 🙂

    Reply
  40. CaSH_2004

    Интересно как это у всех работает, а у меня нет? Скачал последнее — все описанные выше поправки имеются — ни фига не работает!

    У меня Контрагент + Банк. счет + Договор, ссылок на подчиненные нет, провериил лично

    В коде нигде не нашел чтобы подчиненные проверялись на наличие на них ссылок! Однако прочитав внимательно описание:

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

    понял что принял желаемое за действитеьное.

    Итак что же делать уважаемый defender? Как это может оказаться что есть помеченные на удаление подчиненные элементы, а сам Владелец нет? Это однако нонсенс если не говорить о выборочной пометки вручную.

    Все обычно как раз наоборот — все непомечены на удаление, и надо найти и пометить их.

    Итак предлагаю это исправить на первый раз так, находим:

    ИначеЕсли Найти(строкаТипа, «Справочник.») > 0 Тогда
    Если Стр.Данные <> мО И НЕ Стр.Данные.ПометкаУдаления Тогда

    меняем на

    ИначеЕсли Найти(строкаТипа, «Справочник.») > 0 Тогда
    Если Стр.Данные.Владелец <> мО И Стр.Данные <> мО И НЕ Стр.Данные.ПометкаУдаления Тогда

    Это конечно половинное решение, т.к. даже если Владелец не присутствует например в документах, то например банк.счет может, но если исходить из следующих моментов:

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

    2. Удалять все равно желательно через монопольно или спец. обработкой с ИТС и проблем не будет т.к. я доверяю только таким методам

    3. Банально нет времени все сделать правильно, однако если автор не против можно чуток доработать и выложить, вообще стоит наверно когда выкладываете свои доработки сразу оговаривать возможность доработки другими разработчиками, а то устаеш всех спрашивать «можно?», а без спроса как-то неудобно

    Reply
  41. clab

    На больших объемах виснет и вылетает.

    Reply
  42. defender

    Падает платформа из-за нехватки памяти. Из-за этого и сделана возможность проверять определенную папку, а не только справочник целиком.

    Reply
  43. AnryMc

    Попроще, но раньше…

    http://infostart.ru/public/65132/

    Пока не висла ни не вылетала

    Reply
  44. leks88

    Работает великолепно! Очень быстро, в отличии от других аналогичных, на БП 2.0.48.7 Автору плюс и большое спасибо

    Reply
  45. kvp

    Благодарю, отлично.

    Reply
  46. Рамзес

    Спасибо, хорошая обработка! Но не хватает отборов!

    Reply
  47. defender

    (47) Рамзес,

    не могли бы мысль несколько развернуть? Что отбирать, как и зачем?

    Reply
  48. Рамзес

    (48) доработал, выложил http://infostart.ru/public/264964/

    Reply
  49. CaSH_2004

    (49)Уважаю за доработку и публикацию, побольше бы таких адекватных

    Reply
  50. CaSH_2004

    (48)Забавно слышать от 1С-ника что такое отбор и для чего он. Представьте справочник в 1 млн. записей и в базе порядка сотни пользователей работают — как будете чистить справочник?

    Reply
  51. Istur

    В строке 224 ошибочный код. Есть:

    строкаТипа = Строка(ТипЗнч(Данные));

    он не работает, надо:

    строкаТипа = Строка(стрМета.ПолноеИмя());
    Reply
  52. fokin

    скажите, а как решается вопрос в (24), у меня просто такая же проблема — ищу решение, зазря качать не хочется

    Reply
  53. apostal86

    Что обозначает настройка «Ограничивать количество ссылок»?

    Reply
  54. defender

    (54) В списке ссылок на выбранный объект показывает первые 100 ссылок, а не все. Полезно когда ссылок много

    Reply
  55. TABEZI1234

    (55) Здравствуйте.Например , я хочу удалять элементы справочников до 2018года; в какой функции вашей обработки нужно делать изменения?

    Reply

Leave a Comment

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