<?php // Полная загрузка сервисных книжек, создан 2026-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='\
Баян же. Было обсуждено уже N раз.
(1) Yashazz, пруф?
(2) Подтверждаю, что баян — поиск по сайту и форму в помощь. Решение само по себе имеет право на жизнь. Эту проблему каждый решает по своему. Я, например, предпочитаю тематические регистры сведений с явной типизацией полей
(0) Правда баян. Если придумал сам — молодец конечно, но иногда нужно ознакомиться с лучшими практиками и другими мнениями. Поиск в руки с тегом «НайтиПоНаименованию». Здесь обсуждали твой способ:
(6) да ты не воспринимай в пику. Я и сам так делаю, только названия справочника и реквизитов другие. Весь вопрос в том, что этот способ известен очень многим, и довольно часто обсуждается.
Доработаешь статью с учетом рекомендаций из переписки по той публикации — тогда будет здорово.
В частности — про общий модуль с кешированием возвращаемых значений для ускорения работы и улучшения читабельности кода.
(3) Артано, в (2) я уже запрашивал пруф. Вы его тоже не смогли предоставить. Поиск по «ссылка на конкретный элемент» ничего не даёт.
Друзья, логика проста: есть пруф, подтверждающий баянность — статья удаляется. Если вы в кулуарах где-то что-то обсудили на эту тему , извините, это известно только вам. Если решили иначе (через РС, например), то это другое решение со своими плюсами и минусами. Например, пользователь может ввести вторую строку или же при обмене данными они могут задвоиться. Т.е. потенциально это решение может привести к ошибкам.
В автор предлагает аж три решения. Первое и третье — модификация стоящих на поддержке объектов, посему лично для меня неприменимо. Второе решение: ПВХ + РС + код. Оно сложнее в реализации и содержит те же потенциальные ошибки, что я описывал выше применительно к РС.
ps: Замечу сам, чтобы быть первым. 🙂 Предлагаемое мной решение методологически верно не на 100%. Какой-нибудь преподаватель УЦ может сказать, что именно для таких случаев со значениями составных типов и создавались ПВХ: они позволяют жёстко определить, что такой-то параметр имеет такой тип, а другой параметр — иной. Возразить могу только то, что элементов в таком справочнике мало, а тип явно указывается в описании. Это не оставляет шансов пользователю накосячить.
(5) cleaner_it, аккурат в предыдущем посте я обсудил эти «лучшие практики».
(7) cleaner_it, я спокоен. Отвечаю на всё, потому что самому интересно, есть ли лучшие решения.
Мысль неоднозначной полезности, пожалуй. На моей практике нет таких случаев, когда бы я получал значение такой ссылки много раз за сеанс. Даже если идёт работа в цикле, то логично получить значение в переменную перед циклом и использовать в цикле её.
Соглашусь, что «баян», ибо такая тактика вообще очень не нова — в 1с77 все ссылки в коде делались именно через подобный механизм… В основном это происходило через добавление новой Константы… но и через справочники — тоже…
Если предопределённых элементов в конкретной базе предполагается немного, то можно по-старинке воспользоваться именно Константами… аналогично ОсновнойСклад и ОсновнаяФирма…
Регистр сведений в таких случаях получше
использую НайтиПоНаименованию() без зазрения совести после того, как на небольших внедрениях понял, что клиенту надо «быстро» и без особого вмешательства в конфигурацию (добавлять постоянно предопределенные элементы — это значит просить всех пользователей выйти), что основополагающие для учета требования клиента меняются условно «раз в 5 лет» и вся запрограммированная система стабильно работает длительное время. плюсов в предопределенных элементов не вижу, если только в типовых конфигурациях ЗУП и БП со своими сложными расчетами з/п и составлением деклараций.
в общем не стал заморачиваться с НайтиПоНаименованию().
информация в статье для меня новая, не могу сказать что баян, и в целом реализация мне нравится.
(10) Fannasankh, а почему?
(11) Только НайтиПоНаименованию(), только хардкор!
+ за статью.
как — то на эту тему не думал . найтиПоНаименованию, найтиПоКоду пока работает )
Решение имеет право на жизнь. Я использовал по другому:
1) раз справочник все равно служебный и пользователю запрещено добавлять в него элементы, то предопределенные элементы не обязательны и не требуется выгонять пользователей при добавлении нового элемента. Сама же ссылка настройки без проблем получается через НайтиПоКоду
2) Нет возможности учета истории. Часто история все же нужна. Для этого есть доп. периодический регистр сведений.
Пользователь к ошибкам привести не может, т.к. прав интерактивного редактирования РС у него нет.
3) Еще, если добавить в РС группу пользователей можно разграничивать настройки между пользователями. Для общих настроек — все пользователи.
В типовых, когда изменения конфигурации запрещены, использовал ХранилищеЗначения в типовых справочниках хранения настроек. Нет контроля ссылочной целостности, но лучше чем НайтиПоКоду и настраивать можно.
Еще можно использовать метод ПолучитьСсылку менеджера и передавать в нее ИД, тогда получится близкий аналог предопределенного элемента, т.к. обращения к БД не будет и ссылка везде будет иметь одно и то же значение.
В любом случае такого рода приемов подразумевает инициализацию подобных элементов в новой базе, либо использование ее только в семействе уже инициализированных баз с общими данными этого типа.
(16) tormozit, этот способ описан в комментариях к упоминавшейся статье. Я согласен к комментаторами, что он ничем не лучше НайтиПоНаименованию().
Зачем все это? Есть же все в платформе.
ИМХО, при грамотном подходе к проектированию решений эти «обходные» пути не пригодятся.
Юзаем такой справочник уже не первый год)
(19) Патриот,
Аналогично )
Кстати, в решениях Первого БИТа видел не справочник, а ПВХ — так, наверное, все же более правильно.
Еще проще вынести в отдельную процедуру. Менее концептуально, зато больше возможностей, например в зависимости от даты или других параметров можно подставлять. Такой метод считается «не кошерным», только из за того, что в пользовательском режиме нельзя менять настройки. Но если эти «константы» системные, и пользователю к ним доступ давать не следует, как раз самый простой вариант.
А почему все это не вывести в реквизиты обработки и загружать при открытии и сохранять при закрытии.
Если появиться новый пользователь один раз ему поставить эти значения и ВСЁ.
На крайний случай искать через ПОПЫТКУ по наименованию.
И лесть в конфигурацию?
У себя применяю ПВХ, 2 регистра: «Предопределенные элементы» и «Предопределенные списки» и общий модуль, в котором все это дело получается.
В результате можно хранить как одиночные значения (на замену константам), так и списки этих значений, в том числе упорядоченные.
Периодичность значений пока не требовалась, но допилить не сложно.
Если руки дойдут, может выложу и свой вариант 🙂
(15) Totoro,
К пункту 1. Поскольку добавление нового элемента всегда связано с изменением кода (нет смысла добавлять новый элемент, если на него нигде нет ссылок, а ссылки для этой задачи могут быть только в коде), то какая разница для чего выгонять пользователей — только для обновления кода конфигурации, или для изменения кода конфигурации плюс добавление нового предопределённого элемента?
(24) для внешних печатных форм, обработок и отчетов изменения кода не требуется, а константы нужны/удобны.
(18) bpc222, +
эммм… возникает вопрос удаления обхекта на которого в специальном справочнике есть ссылка, тут наверное два варианта, либо РС со свойством «Ведущее» и измерения СсылкаНаобъект, либо вместо ссылки писать тип и уид.
А вообще если говорить про обычные формы, во всех конфигурациях есть РС «Сохраненные значения», в управляемых формах стал пользоваться хранилищами значений.
Правильной дорогой идете товарищи, защита от говнокодеров нужна! Статья хорошая.
Но, как уже было замечено, нельзя «про запас» накидать предопределенных элементов, нужно при возникновении потребности лезть в конфигуратор. При наличии РИБ — и не в один. Чем не вариант добавить ПВХ (пользователю недоступный), в котором на лету создавать необходимые записи и в коде нетленных отчетовобработок ссылаться через (чую смерть моя близка!) НайтиПоНаименованию (или Коду) на свежесозданный элемент ПВХ…
PS. ПВХ в твоем полном распоряжении, изменил чего — ну кто тебе доктор…
PPS. Если группа разработчиков — и так должно быть понятно к каким последствиям может привести правка Наименования (Кода) именно этого ПВХ…
PPPS. Вместо ПВХ никто не запрещает использовать Справочник, как у автора…
PPPPS. При желании можно привязать историю правок…
Плохой совет! Во многих, если не во всех типовых конфигурациях(Бух, УТ, КА, ЗУП), есть регистр сведений «Соответствие объектов для обмена», вот его и нужно использовать для подобных целей. Все поля не обязательны для заполнения. СобственнаяСсылка — «ЛюбаяСсылка», СсылкаВДругойИБ — Строка(100), ИмяТипаПриемника — Строка(100). И не ограничены цели, для которых этот регистр будет использоваться. И самое важное, закройте конфигуратор!)
(29) rar_xxx,
Как ссылаться на конкретный элемент? НайтиПоРеквизиту или даже запросом?
Как убедиться, что нужный параметр присутствует в РС?
Как убедиться, что нужный параметр присутствует в одном экземпляре?
Не вижу плюсов данного варианта при наличии такого количества минусов.
(30) 1. Все делается запросами. 2 — Запросом. 3 — запросом. Выдуманные минуса, ровно как ты добавляешь предопределенные в справочник, так же добавляешь элементы в регистр. Хочется обращаться в запросах через НазваниеСправочника.НазваниеЭлемента, перед запросом получаешь все нужные значения и засовываешь их как параметры. Но + в том что если ты когда то работал с базами которые работают 24*7, то должен понимать что для полноценной безостановочной работы подходит только мой вариант.
(31) rar_xxx, я не говорил, что решение подходит для баз 24*7. Наоборот, в комментариях я упоминал, что настанет момент применения изменений в базу. Вполне вероятно, что для такого редкого случая как ОП типовая в режиме 24*7 этот способ является оптимальным. В остальных случаях лично мне он кажется более ресурсоёмким для 1С и менее надёжным при программировании, т.к. названия приходится вписывать ручками в текст и легко можно ненароком изменить их в регистре. По сути он мало чем отличается от НайтиПоНаименованию.
А чем плох поиск по GUID? Типа — Справочники.Склады.ПолучитьСсылку(Новый УникальныйИдентификатор(«cc1dd491-c7d8-11a2-f90a-1c7ee5263dff»))
(33) capone, тем, хотя бы, что в запросе этого использовать нельзя. И я очень бы хотел посмотреть на Вас, через пол года, когда в алгоритм надо будет внести изменения. Т.е. к вашей конструкции еще ворох комментариев нужен как минимум. Да и GUID это вещь постоянная — относительно, имеется опыт…
(32)
Отличается тем что наименование может меняться, а в регистре сидит ссылка.
. Первое преподователь из СЦ не даст жизнь твоему решению, а если ты подобное на экзамене специалиста сделаешь снимут бал, ибо 1ое — изменение типовых конфигураций 1с не приветствует, 2ое — изменение конфигурации при возможности использования типовых объектов не кто не приветствует, мой метод простой,
при создании предопределенного ты имя не руками пишешь? Для самоконтроля сделай себе обработку по работе с этим регистром, придумай ИмяТипаПриемника — «мои переменные» и выводи в обработку список всех своих переменных, где будут проверки на задвоение и т.п. И еще кроме 24/7, есть еще базы >=100 Гб, а еще есть регламенты согласно которым каждое изменение ты утверждаешь с рук. отдела, такие изменения не разрешат.
(35) rar_xxx,
Ссылку на строковое значение объекта мы заменяем на ссылку на строковое значение регистра. Суть не меняется.
При чём тут преподаватели или руководители отдела? Это наглядный пример задействования объекта, предназначенного для одних нужд, для реализации других. Я склонен считать такое решение методологически некорректным. Из практики 1С не могу вспомнить конкретные примеры, но из практики IT помню, как один клиент хранил важные документы в «корзине». До тех пор, пока другой, не подозревая об этом, не очистил «корзину». Аналогия, думаю, понятна. Удачи.
(36)
я предлагаю сделать ровно то что предлагаешь ты, привязать к ссылке свое наименование, чтобы при изменении наименования объекта код работал. И где здесь
?, этот регистр необходим для обмена, чтобы всякие правщики конфигураций, не добавляли реквизиты к метаданным с названиями «idТам», «IdдругойБазы» и т.п. После которых на базу смотреть невозможно! Задача у меня следующая: я — другая ИБ, у меня есть справочник переменных, хочу хранить связки своих переменных с ссылками в тек. базе, например: id моей ИБ — «Склад поступлений», ИмяТипаПриемника — «Мои переменные». Иногда надо послушать людей и подумать, а не с пеной доказывать свою точку зрения. А связывать это регистр с корзиной не корректно, то что он может бесконтрольно очистится говорит о кривом использовании базы. Когда строишь обмены между кучей систем, не только 1с, с помощью правил КД и использованием данного регистра, трогаешь его ООООооочень аккуратно! И еще
равносильно
и равносильно
В любом случае это превращается в запрос. Соответственно если регистр Соответствие объектов для обмена пустой то скорость работы этих 2х решений аналогична. Ща поговорил с 2мя напарниками имеющими звание — «Специалист 8.3» их перекосило от вашего метода, выводы делайте сами, но советовать надо когда 100 есть процентов уверенности в своем мнении…….
Сколько можно обсасывать одно и то же? Было и гораздо более развернуто
(37) rar_xxx, Вы позволите мне остаться при своем мнении или я обязан принять Вашу точку зрения? Я уже высказал свои доводы и не увидел веских аргументов. Предлагаю прекратить попытки.
(33)Тем что строка Справочники.Склады.ПолучитьСсылку(Новый УникальныйИдентификатор(«cc1dd491-c7d8-11a2-f90a-1c7ee5263dff»)) не говорит не о чем и глядя на код чуть позже ты долго будешь втыкать что же стоит за этим гуидом, а если таких гуидов больше чем несколько, то рассматривать такой код совсем печально.
(34)
Гуид вещь постоянная, которая штатными средствами(если не лазить немытыми руками напрямую в базу) не меняется в принципе.
(37)Если мягко сказать вы неправы. Во первых наименование, это такая вещь, когда каждый пользователь может просто добавить туда пробел и ваш код перестанет работать. За работу с поиском по наименованию, били по рукам, еще во времена 77 и предопределенные элементы нужны как раз для того, что бы их заменить. Во вторых это
равносильно
«Выбрать Ссылка Из Справочник.МойСправочник Где Наименование = «»МоеНазвание»»»
и равносильно
Справочники.МойСправочник.НайтиПоНаименованию(«МоеНазвание»);
тоже мягко говоря не так
(40) webester,
Речь идет про справочник который хранит ссылку на необходимые объекты, обращение и поиск в этом справочнике идет по имени, например Справочники.МоиПеременные.СкладПродаж. 2 — я ошибся в плане скорости обработки 1с, если смотреть в анализатор запросов sql эти 3 метода идентичны, разница во времени выполнения 1с, заключается в том что при формирования запроса sql все названия таблиц, колонок, справочников меняет на реальные, а это еще заросы к таблице соответвия имен метаданных их реальным именам поэтом кло-во действий при обращении через точку меньше всего, через найти по наименованию изменений немного, а в случае запроса анализируется и изменяется весь его текст. Кстати в 8.3 переработали и теперь можно делать предопределенные элементы в нужных справочниках, не заходя в конфигуратор, так что больше не нужно создавать свое хранилище переменных.
(15) 1. НайтиПоНаименованию() лучше будет, и длиннее идентификатор можно делать и понятнее при чтении кода.
2. Историю вполне можно хранить в табличной части справочника, добавив реквизит «Период».
3. Права доступа можно при необходимости организовывать — в еще одной табличной части.
(41) rar_xxx, итак, разница в скорости есть. «Новый» способ создавать предопределенные элементы далеко не такой новый. Он был подробно рассмотрен в упоминавшейся мной статье (3 вариант) на ту же тему и отклонен как требующий включения возможности внесения изменений в объект конфигурации. Напомню: «но советовать надо когда 100 есть процентов уверенности в своем мнении». Привет «специалистам».
(42) DrAku1a, методологически Вам нет оправдания. Нежелание включать возможность изменения для объектов не должно приводить к созданию таких некорректных решений. Эмулируем регистр сведений при его жизни? Игнорируем RLS? Я считаю, не стоит.