<?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='\
Хорошее решение, разве что только скобки () глаза мусолят, но это терпимо.
Вот бы сделали «свойства», как в C#. С виду, обычные поля, а на деле — методы.
Хотя, если уж вносить изменения в встроенный язык 1С, то относительно этой задачи, надо сразу enum’ы делать.
Главная проблема, что для этого перечисления не сработает контекстная подсказка. Т.е. все равно придется идти и смотреть, какие значения бывают, копировать, вставлять…
Актуальная проблема. Исходя из собственного опыта, лучше все настройки, в том числе и сравнения «повесить» на пользователя. Назначить ответственных за механизмы/процессы. Для этого лучше всего сделать справочник или несколько с набором реквизитов/табличных частей для различных настроек. И настройки получать, например, ПриНачалеРаботыСистемы()
(4) Ну, тут речь не совсем об этом. Вам к уже введенным настройкам надо как-то обращаться в коде. То что должен быть момент передачи ответственности — полностью согласен, как и с тем что лучше такое реализовать пользовательской настройкой. Только имхо, это не взлетит в 90% случаев фикси. Но это уже тема для отдельной беседы)
(1)
— можно уточнить о чем идет речь ? (обсуждается какая-то публикация ?)
Что-то на ИС с комментариями, не видел (1) и (2)
(1) Ну да, мозолят) Идея использовать структуру для этих целей и появилась после того как прочитал чей-то коммент про отсутствие таких вещей в 1С, там тоже человек с любовью С вспоминал)
(6) я так понимаю, текущая 😉
автор забыл ссылку на публикациюhttp://infostart.ru/public/566908/ ?
(8) это скорей не автор забыл, а движок инфостарта заглючил…
Если взять не общий случай — ветвление кода, а частный — выбор набора параметров или макета, то чем плох обыкновенный справочник?
Это очень хорошо, если во входящем файле статусы заявок без пробелов записаны. А если с пробелами, как тогда поступать?
Идея конечно интересная.
Честно говоря, профита не так много как хотелось бы.
Но уже одно то, что в рантайме упадет сразу в том месте, где была ошибка в названии перечисления, дорогого стоит.
Т.е. в сложных случаях имеет смысл использовать. В простых — вряд ли.
(8)(10) не понял вопросов?
(11) Любую коллекцию параметров удобно так использовать — посмотрите последний пример с планом счетов. В примере — сравниваются значения структуры. Ну добавьте такой элемент:
(13) Основной профит — в удобной структуре кода. Кроме того, автоматически получается оптимизация — в том смысле что коллекция параметров не будет рассчитываться по 10 раз подряд. Неоднократно видел как люди в цикле пишут что-то вроде сч70_1_1 = ПланыСчетов.Хозрасчетный.НайтиПоКоду(«70.1.1»).
В каких случаях использовать — я теперь только так работаю, если есть несколько строковых констант, даже не задаюсь вопросом «надо ли». Это похоже на рассуждение: «зачем оформлять код по правилам ИТС, для своей разовой доработки?» — т. е. человек не понимает зачем вообще его нужно оформлять, не видит в чем удобство. Я например даже для небольших работ все оформляю — это копейки времени, которые окупаются с лихвой если из разовой доработки понадобится ваять что-то серьезное, или передать кому-то на анализ, или вспомнить что делалось через полгода. Это на подкорке. Чтобы я забыл код оформить — никогда такого не было. Также и здесь. Но это конечно мое «имхо»)
Может, лучше использовать соответствие ?
Синтаксис похожий, плюшек больше.
Подходит для больших списков.
(15) «Основной профит — в удобной структуре кода». Не согласен. «Структура кода» удобнее не становится. Я не про счета и кэширование (это уже несколько про другое), а про саму идею программных перечислений. В плане удобства — получаем сомнительный аргумент «красивенько» против дополнительного времени на реализацию и въезжание постороннего программиста в этот код. Вот своевременное падение в рантайме для легкого поиска ошибки — это профит. Если бы во время компиляции ругалось — это вообще был бы всем профитам профит. А если бы еще и автокомплишн в конфигураторе — практически полноценные перечисления бы вышли.
(17) Именно в нем. «Тупой код с хорошей структурой, лучше чем тупая структура с гениальным кодом». Про время на реализацию — расхожее заблуждение. Дровосек рубит деревья, у него спрашивают — мужик, че ты мучаешься, у тебя ж топор тупой. Наточи топор. А он отвечает: «мне НЕКОГДА! мне надо РУБИТЬ». И все «рубят». Код должен читаться как книга.
По приоритету, для меня так:
— «въехать» в это можно достаточно быстро
— при этом можно быть уверенным что коллекция заполняется только в одном конкретном месте, благодаря использованию фиксированной структуры
(16) Используйте то, что вам удобнее) Но соответствие не выдаст исключения при получении отсутствующего значения, а вернет неопределено. У него несколько иное назначение, чем у структуры.
Идея хорошая, но все же ИМХО лучше один раз вызвать функцию и вернуть в локальную переменную структуру и работать с ней, чем 10 раз вызывать и проверять, проиницилизирована ли нужная нам структура.
Но это так просто придирка, хотя когда подобных структур будет достаточно много (хотя я даже не представляю себе род такой задачи), поиск и копирование структур может стать достаточно ощутимым.
(20) Тут как раз все в порядке.
Во-первых, ленивая инициализация — это само по себе хорошо.
Во-вторых, явная инициализация на старте — это еще одна «точка привязки» в коде для реализации этой концепции. Абсолютно лишняя.
ЗЫ. Поиск в структуре по ключу не должен стать ощутимым, даже если ключей будет много. Если я правильно помню — это хэшированная структура данных. Ну, разве что свопить начнет 🙂 А копирования тут нет.
Мне кажется, что автор начиная со первого примера «СтруктураСтатусыЗаявок» забыл про своё-же замечание: (буква «О» <> «о»).
А можно функцию СтатусыЗаявок() разместить в глобальном общем модуле с повторным использованием возвращаемых значений на время сеанса?
Тогда и переменная мСтруктураКэшПрограммныхПеречислений не нужна и можно будет использовать СтатусыЗаявок() в других модулях.
Например если я хочу передать СтатусыЗаявок().Отказ в качестве параметра из другого модуля, то в другом модуле функцию СтатусыЗаявок() не видно. А если разместить ее в глобальном модуле, то будет видно.
unichkin, Что об этом думаете?
(0) Более другой вариант.
Заполнять такие перечисления в таблицы на форме, проводить программное сопоставление, окончательную корректировку оставлять пользователю.
Обработку данных производить с учетом полученных таблиц соответствий (количество значений в которых неопределено и разработчика не волнует — он работает со стандартным справочником/перечислением из соответствия)
в таком варианте снижается требование к качеству заполнения таблицы для загрузки.
тавар ф пути
номенклатуро в перевозке
и ТоварВпути
обработаются одинаково корректно.
(23)
— не вижу ошибки, ткните пальцем если не сложно.
(24) Я думаю, если дорабатываете конфу — то добавьте нормальное перечисление.
Этот способ хорош для константных значений, уникальных в каком-то определенном алгоритме (внешнем или внутреннем). Например — статусы заявок приходят к нам в виде текста. Но в конфигурации это наверняка перечисление. Здесь структура нужна только для того, чтобы удобно и качественно проверять все входящие значения статусов.
Еще пример с потолка (кривая методология, просто чтобы отразить суть вопроса): скажем в документе оператор заполняет строковое поле «Причина отказа». Причина может вводиться как из заранее определенного списка, так и произвольно — если установлен соотв. флаг. Так вот — если не добавлять в конфигурации нормальное перечисление (а лучше добавить, сделав «причину» составным полем), то да, наверное логично так сделать. Только модуль ПовтИсп хранит кэш 20 минут. Возможно лучше использовать какие-то существующие кэши конфигурации. И «мСтруктураКэшПрограммныхПеречислений» не будет нужна только для этого конкретного случая.
(25) Если рассуждать только с позиции загрузки заявок — то конечно, да, лучше дать на откуп пользователю. А еще лучше проговорить это все в ТЗ. Потом при формировании структуры перечисления собрать данные из таблицы формы — да, логично, почему нет. Но загрузка заявок — это ведь частный случай, я его использовал для примера. У меня например была задача, в которой я создавал программное перечисление для событий журнала регистрации. Т.е. было примерно так:
Потом для фильтров использовал СобытияЖР().Проведение и т.п.
Если инвертировать проверку свойства в мСтруктураКэшПрограммныхПеречислений, то это позволит уменьшить уровни вложенности и код будет читаться легче. Сравните:
Показать
(28) Я обычно стремлюсь к сокращению «Возвратов», если можно рассчитать значение внутри функции и вернуть результат в конце метода — так и делаю; приведенный вами код не кажется мне более читабельным решением, может дело вкуса. Делайте как вам удобнее) Я останусь при своем.
Кстати, сейчас подумал — что в функциях обычно минимизирую возвраты, а в процедурах как раз наоборот — если есть условие прерывания, стараюсь выполнить его в самом начале, чтобы не использовать лишних расчетов.
(29) Единая точка выхода, ага, нас тоже так в школе учили. Но если уж вы предлагаете способы, как улучшить читаемость кода, идите дальше. Согласен, в приведённом мной примере данное изменение не сильно улучшит читаемость, но примените его к вашей функции ИспользуемыеСчета(), и там такое улучшение будет уже более актуально. Матчасть:Замена вложенных условных операторов граничным оператором.
(30) Да нет в «ИспользуемыеСчета()» ветка условия всего одна, так что принцип тот же что и в (29). То, что описывает приведенная вами статья я стараюсь соблюдать, и это как-то всегда на уровне спинного мозга осознавал — что не стоит допускать дебрей
Case-OfЕсли-Тогда. Однако за наводку и интерес к моей статье — спасибо)Мне в данном конкретном случае кажется более логичным заполнять структуру именно внутри условия. Возможно потому, что основные цели этих методов (для вызова программного перечисления) — это заполнение соотв. кэша, и более логично в начале алгоритма видеть инициализацию коллекции по условию ее отсутствия. Тут с т.з. рефакторинга было бы неплохо вынести код по заполнению структуры счетов в внешний метод, но я не люблю перегружать программный интерфейс методами (пусть даже и служебный). Т.е. использоваться -то он будет все-равно только в одном месте. Вот если его глобальным сделать, тогда другое дело. Было бы нечто вроде такого:
Показать
Понимаю что поздновато отписываюсь, но как вам такой вариант?
Показать
Плюсы:
1. Можно использовать в формах &НаСервере, вместо того чтобы каждый раз инициализировать переменную после клиента;
2. Есть автодополнение и контекстная подсказка;
3. Если даже набрать имя функции неправильно — ошибка всплывет на этапе синтаксической проверки (при отладке вашего способа не всегда может получится все ветки прогнать, и до ветки с ошибочно набранным значением можно не добраться)
4. По идее возвращаемое значение таких функций должно «инлайниться» в место использования, так что производительность должна быть такая же как при обычном сравнении со значением, а если и нет то что у меня, что у Вас накладные расходы на вызов функции так или иначе идут.
Минусов с ходу могу назвать только два:
1. Засорение контекстной подсказки, для чего и добавил в начало _;
2. Такое «перечисление» не передашь в другой модуль, разве что вместе со всем текущим контекстом (ЭтотОбъект придется передавать из общего модуля или формы) и делать данные функции экспортными.
(32)
1. Объявляете реквизит формы «СтруктураКэшПрограммныхПеречислений», с произвольным типом реквизита… А остальное все то-же) Это если для формы. Вообще правильнее все-же к форме относить то, что касается *формы* — интерактив, все расчеты лучше отправлять на сервер, т.е. в модуль объекта. Ну тут можно много рассуждать и говорить — по всякому можно. Если говорим о внешней обработке можно сделать реквизит обработки произвольного типа — он будет доступен и с сервера и с клиента. Если о объекте конфигурации — сделайте реквизит формы. Или — вызов из модуля ПовтИсп.
2. Если учесть что различие только в префиксе — имхо, не очень удобно для набора, когда много коллекций.
С моей точки зрения, когда перечисление обосабливается в свой метод — это и нагляднее и удобнее. Ну да, синтакс контроль не заругается. Пишите аккуратнее) Каждому свое конечно, используйте то что вам больше подходит. Но мне с таким кодом было бы работать тяжеловато. Подчеркивание в начале метода — это нарушение правил образования имен переменных. Ну и плюшки с ленивой инициализацией теряются.
>через предопределенный список элементов плана счетов, т.е. туда надо провалиться, найти код счета, скопировать имя… — долго
на этот случай имена счетов сохранены в отдельном файлике, открыл, скопипастил
Красиво и лаконично! Молодца!
Возможно, я чего-то не понял, но мне кажется в коде примера использования ошибка.
Строка «ВидОпределенияКонтрагента = ВидыОпределенияКонтрагента().Контрагент;» не корректна, т.к. структура СтруктураВидыОпределенияКонтрагента не содержит свойства «Контрагент», зато содержит «Документ».
И чтобы сработало вот это:
Если СвойстваИсточника().ВидОпределенияКонтрагента = ВидыОпределенияКонтрагента().Документ Тогда
Контрагент = мИсточник.Контрагент;
наверное, нужно было написать так:
Если ТипЗнч(мИсточник) = Тип(«ДокументОбъект.РеализацияТоваровУслуг») Тогда
ВидОпределенияКонтрагента = ВидыОпределенияКонтрагента().Документ;
Сори, если туплю…
Но может кому сбережет нервы при копипасте примера 🙂
(11) не надо останавливаться на приведению к какому то регистру, надо еще удалять крайние пробелы и заменять два пробела на один дважды, тогда строка боле менее приводится к нормальному виду.
(36) Все верно, спасибо, поправил
Идея неплохая,но вообще удобнее чем работать с макетами в которых все зашито ничего опытным путем найдено не было.
Прошу прощения за глупые вопросы. Но вся суть это длинной статьи, отсылки на вики, простыней кода, заключаются в фразе: «Если вам нужно использовать несколько строк в операторах сравнения, используйте структуру» ? Или я чего то не заметил?
Отменил свой коммент
Если религия не запрещает, то можно использовать сами чистокровные перечисления без регистрации, смс и совершенно без серверных вызовов, спросите как? Очень просто!
1) Создаем реквизит формы произвольного типа, Назовем её к примеру «Переч_Статусы»
2) При создании формы на сервере (или любой другой метод, выполняющимся одним из первых на сервере) выполняете такой код для нужных перечислений:
Показать
Если перечислений много, можно использовать фиксированное соответствие, так вообще будет похоже на штатное перечисление
3) Там где надо получить значения перечисления пишите так:
Так можно без вызова сервера проверять/устанавливать значения перечислений, единственный минус, это отсутствие подсказки, но если вы ошибётесь в копипейсте значения перечисления при вставке в код, то так-же как и в данной публикации, будет выдана ошибка при выполнении.
PS: Так как это реквизит формы, а не переменная, то данный код можно использовать и на сервере (дабы не мучить базу лишними запросами).
(42) Клиент-серверный кэш на форме нужен крайне редко. Кэшировать именно значения предопределенных элементов значения перечислений самостоятельно не требуется — для этого есть метод «ПредопределенноеЗначение». В том случае если на форме нужен кэш — это бывает, когда архитектурно невозможно вынести код в модуль объекта, можно также использовать глобальную переменную (в данные формы таблицу значений например не поместишь). Я это делаю примерно так:
Показать
(43)
я возможно сделаю для вас открытие, но данный метод делает серверный вызов и если сервер рядом, этим можно и пренебречь, но я как-то заметно ускорил РМК из 1С:Розница 2.2 особенно на слабом интернете, заменив ПредопределенноеЗначение на нечто подобное описанное в (42) ничего не потеряв при этом.
(44) я руководствуюсь этой статьейhttps://its.1c.ru/db/v8std#content:443:hdoc
«При этом не следует в прикладном коде реализовывать собственные механизмы кеширования на клиенте предопределенных значений. Функция ПредопределенноеЗначение не ухудшает клиент-серверное взаимодействие: серверный вызов выполняется только при первом обращении к значению, а результат автоматически кешируется в кеше конфигурации на клиенте до следующего обновления версии конфигурации или версии платформы.»
з.ы. не умаляю ваших результатов, но по своему опыту — сначала делаю как сказано на ИТС, если не катит начинаю изобретать велосипеды. А «не катит» довольно редко, до сих пор только один случай могу вспомнить.
(45) По моему субъективному опыту, кешируется на время сеанса. И это кеширование несколько дороговатое, если можно это сделать самостоятельно, один раз и при создании формы на сервере. Я ни чуть не осуждаю вас, но к сожалению должен констатировать, что 1С делая Розницу, походу полагала что сервер будет находится за стенкой с гигабитной сетью и будет всего один магазин. И там много где используются избыточные вызовы сервера и много где используется в том числе ПредопределенноеЗначение на клиенте. Даже просто запуск сеанса в рознице и то удалось сильно ускорить (не смотря на то, что там ещё и мои обработчики навешаны по мимо типовых) заменив в куче мест вызовы модулей с галочкой «вызов сервера» и даже с галочкой «повторное использование» заменив всё это тем, что получаю все эти необходимые значения в типовую глобальную переменную «ПараметрыПриложения» один раз, делая один серверный вызов и просто в местах где это вызывалось, заменил на получение значения из этой клиентской переменной. Конечно, таким способом можно ускорить только получение некой статичной информации, но я даже некоторую потенциально не статичную информацию засунул туда, только сделал кнопочку «Обновить» на всякий случай, которая требуется раз в пятилетку.
PS: Но в любом случае, спасибо за ссылку!
Да, ещё хочется припомнить 1С один курьёзный случай в РМК (Розница 2.2), точно его не помню, по этому опишу по своему:
Показать
И вот этот «НайтиЭлемент» вызывался на клиенте при наборе и пробитии одного чека что-то около 40 раз. Мне даже те кто пользуются файловой базой, начали жаловаться на тормоза. Что уже говорить о том, когда клиент отнесен от сервера на десятки и сотни километров и работает через тонкий клиент. Но это просто у меня наболело, извините