Простой способ убрать префикс и лидирующие нули из номера.




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

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

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

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

37 Comments

  1. aleksey2

    А если префикс = «00» ?

    Reply
  2. Yashazz

    Забавно. Буквально вчера решал эту общеизвестную задачку и думал, как бы поэффективнее. Способ замен, конечно, тоже рассматривал, но… Автор, простите, а если номер «00012034», что будет? Верно, лажа будет. Вот если использовать Лев(,1) и Прав(,1) или новомодные СтрНачинаетсяС и СтрЗаканчиваетсяНа, тогда ещё куда ни шло. А так явный минус.

    Ну и вообще, кажется мне, что не самый это изящный и быстрый способ.

    Reply
  3. alex-l19041

    а зачем изобретать «велосипед», если можно вызвать готовую функцию общего модуля ОбщегоНазначения.ПолучитьНомерНаПечать(документ);

    Reply
  4. bad_boys

    (3) alex-l19041, ОбщегоНазначения.ПолучитьНомерНаПечать(документ) удаляет только ПрефиксПодразделения или ПрефиксИнформационнойБазы… Если вручную бухгалтер поменял префикс на какой захотел, он не удалится стандартной функцией.

    Reply
  5. bad_boys

    (2) Yashazz, функции СтрНачинаетсяС и СтрЗаканчиваетсяНа не на всех релизах конфигурации работают…

    Если номер документа «00012034» после обработки станет «12034», что вполне корректно..

    Reply
  6. c300pm

    в БП 3.0 с нумерацией типа ААББ-000001 корректно работает?

    Reply
  7. bad_boys

    (6) c300pm, не могу сказать не проверял на БП 3.0…

    Тем не менее была просьба доработать такой механизм для печати, поскольку стандартный не отрабатывал…

    Какая конфигурация и какой релиз уже не помню…

    Мой способ не является эталоном, но как мне кажется имеет право на жизнь))

    Reply
  8. 1С_Мастер

    Очевидно, что это вариант не сработает с номером АА-123, так как в нем ни одного нуля нет. Или, например, с номером АА-101 сработает неверно, оставив от него только 1

    Reply
  9. v3rter

    Думаю, более правильно будет просматривать посимвольно справа налево до первой не цифры, затем полученную подстроку чистить от ведущих нулей, например так Строка(Число(«0″+ПромежуточнаяПодстрока))

    Reply
  10. bad_boys

    (8) 1С_Мастер, да на Ваших примерах работать не будет(((

    Reply
  11. bad_boys

    (9) v3rter, согласен Ваш вариант более коректный чем мой….

    Reply
  12. v3rter

    Хотя есть альтернативный способ — выкинуть из номера все нецифровые символы, затем ведущие нули. Недостаток: кривые номера типа Н1АБ0000021 превратятся в 10000021, а не в 21. Такие «чудо-номера» бывают от кривых префиксов при обмене.

    Reply
  13. Yashazz

    (5) не релизах конфигурации, а релизах платформы. Не ниже 8.3.7, ну я и написал, что «новомодные»)

    Хожу второй день и пытаюсь решить задачу в духе работ Ильдаровича. Чтобы стильно и извратно)))

    Reply
  14. Yashazz

    Если исходить из того, что все нецифровые префиксы уже отброшены, то самое топорное решение это Формат(Число(Номер)).

    Reply
  15. v3rter

    (13) Yashazz, Подкину для вдохновения https://meduza.io/shapito/2016/06/21/politehnicheskiy-muzey-nauchilsya-svorachivat-artema-chayku-v-lsdu3 , политота, конечно, но алгоритм многообещающий )

    Reply
  16. Ovrfox

    Вот простой код, который сработает, если номер содержит число.

    Функция ТолькоНомер(ВхНомер)
    Рез = СокрЛП(ВхНомер);
    Ном = СтрДлина(Рез);
    Пока Ном > 0 Цикл
    Если Найти(«0123456789», Сред(Рез,Ном,1))=0 Тогда
    прервать;
    Иначе
    Ном = Ном — 1;
    КонецЕсли;
    КонецЦикла;
    Возврат «»+Число(Сред(Рез,Ном+1));
    КонецФункции
    

    Показать

    Reply
  17. likelol.91

    у меня во всех базах так:

    Формат(Число(Прав(Номер,7)),»ЧГ=0″)

    Reply
  18. ildarovich

    Вот еще варианты:

    Функция ЧислоСправа(Стр, К = 0)
    Возврат ?(Цел(КодСимвола(Прав(«!» + Стр, К + 1)) / 5 — 10.5), Формат(Число(«0» + Прав(Стр, К)), «ЧГ=»), ЧислоСправа(Стр, К + 1))
    КонецФункции

    Функция ЧислоСправа1(Номер)
    Возврат Формат(Число(«0» + Сред(Номер, СтрДлина(СокрП(
    СтрЗаменить(СтрЗаменить(СтрЗаменить(СтрЗаменить(СтрЗаменить(СтрЗаменить(СтрЗаменить(СтрЗаменить(СтрЗаменить(СтрЗаменить(Номер
    , «0», » «), «1», » «), «2», » «), «3», » «), «4», » «), «5», » «), «6», » «), «7», » «), «8», » «), «9», » «))) + 1)), «ЧГ=»)
    КонецФункции
    Reply
  19. v3rter

    Как всегда шедевры. Математики поймут )

    Попробую расшифровать для тех, кому лень разбираться.

    Первая функция: рекурсивно проверяются символы справа налево до первой не цифры,

    затем происходит возврат правой части строки по накопленному значению К;

    ( КодСимвола() / 5 — 10.5 ) возвращает значение от -0,9 до 0,9 для символов с «0» до «9»,

    Цел() отсекает дробную часть, в результате для цифр получится 0, для остальных символов не ноль;

    ?(Цел(КодСимвола(Прав(«!» + Стр, К + 1)) / 5 — 10.5),<не цифра>,<цифра>) базируется на особенности преобразования нуля в булево ложь, а «!» + Стр — подстраховка от пустой строки на входе.

    Вторая функция: все числа заменяются пробелами «матрёшкой» вложенных функций

    СтрЗаменить(СтрЗаменить(СтрЗаменить(СтрЗаменить(СтрЗаменить(СтрЗаменить(СтрЗаменить(СтрЗаменить(СтрЗаменить(СтрЗаменить(Номер

    , «0», » «), «1», » «), «2», » «), «3», » «), «4», » «), «5», » «), «6», » «), «7», » «), «8», » «), «9», » «)

    СокрП отсекает пробелы справа, остаток замереятся через СтрДлина и вырезается часть с середины до конца с позиции +1, где должны начинаться цифры.

    Формат( , «ЧГ=») в обоих случаях убирает разделители разрядов при обратном преобразовании числа в текст, потом что через Строка() «формируется … полное представление в стандартном виде, соответствующем национальным установкам». Или как у Ovrfox в (16) вместо Формат(, «ЧГ=») можно попробовать неявное преобразование в строку «»+Число(

    Reply
  20. NoMax

    Было еще на клюшках

    http://infostart.ru/public/57242/

    Reply
  21. v3rter

    (20) NoMax,

    Было еще на клюшках http://infostart.ru/public/57242/

    Было, да сплыло — нет больше этой ссылки. И вот что там было:

    Функция ClearZero(PERNR)  экспорт
    Воз = PERNR;
    апр=СтрДлина(Воз);
    Для АНК = 1 По апр Цикл
    аст = Сред(Воз, АНК);
    Если Лев(аст, 1) <> «0» Тогда
    Воз = Сред(Воз, АНК );
    Возврат Воз;
    КонецЕсли;
    КонецЦикла;
    КонецФункции
    //В модуле формы ищем поля для которых нужно применить функцию.
    //К примеру нужно чтобы поле  НомерДокумента = Докум.НомерДок; печаталось без нулей,
    //заменяем на   НомерДокумента = ClearZero(Докум.НомерДок);

    Показать

    То есть убираются только ведущие нули, на номерах с префиксами не сработает.

    Reply
  22. m..adm

    (18) ildarovich, Код должен быть читабелен, чтобы не ломать голову в рекурсиях.

    Reply
  23. m..adm

    я бы так отсеивал лишние нули

     НовыйНомер = «»;
    Начнем = Ложь;
    Для Ном = 1 По СтрДлина(Номер) Цикл
    тКод   = КодСимвола(Номер,Ном);
    ЭтоЧисло = тКод > 47 И тКод < 58; //цифры от 0 до 9
    Начнем   = Начнем ИЛИ ЭтоЧисло И НЕ тКод = 48;
    Если Начнем И ЭтоЧисло Тогда
    НовыйНомер = НовыйНомер + Сред(Номер,Ном,1);
    КонецЕсли;
    КонецЦикла;
    

    Показать

    Reply
  24. v3rter

    (23) m..adm, Кстати, это способ, упомянутый в (12), в целом годный, хороший с единственным недостатком

    кривые номера типа Н1АБ0000021 превратятся в 10000021, а не в 21
    Reply
  25. vadim1011985

    Решил и я предложить свой вариант

    Процедура Команда1(Команда)
    
    НомерНаПечать = ПолучитьНомерНаПечать(Объект.Номер);
    
    Объект.Номер = НомерНаПечать;
    
    КонецПроцедуры
    
    Функция ПолучитьНомерНаПечать (Номер)
    
    Пока СтрДлина(Номер)>0 Цикл
    
    Попытка
    
    НомерНаПечать = Строка(Число(Номер));
    
    Возврат НомерНаПечать;
    
    Исключение
    //Если СтрДлина > 0 Тогда
    Номер = Прав(номер,СтрДлина(Номер)-1);
    //  Иначе
    //   Возврат 0;
    //    конецЕсли;
    
    //  Продолжить;
    
    КонецПопытки;
    
    КонецЦикла;
    
    Возврат  «»;
    
    КонецФункции

    Показать

    Reply
  26. v3rter

    (25) vadim1011985, тоже хороший способ. На случай кривых номеров я бы сделал Возврат «________»; чтобы была возможность вписать номер вручную не перепечатывая документ повторно.

    Reply
  27. Ovrfox

    (25) Вы меня мзвините, но этот код не годится.

    Пример Номер А24.0000147. Правильно вернуть 147, а не 24.0000147

    Reply
  28. vadim1011985

    (27) Ovrfox, согласен, есть такое , но опять же можно использовать функцию СтрЗаменить где поменять точки и запятые на какой-нибудь символ. А вообще можно придумать такой пример который с предельной функцией не будет работать

    Процедура Команда1(Команда)
    
    НомерНаПечать = ПолучитьНомерНаПечать(Объект.Номер);
    
    Объект.Номер = НомерНаПечать;
    
    КонецПроцедуры
    
    Функция ПолучитьНомерНаПечать (Номер)
    
    Номер = СтрЗаменить(Номер,».»,»@»);
    Номер = СтрЗаменить(Номер,»,»,»@»);
    
    
    
    Пока СтрДлина(Номер)>0 Цикл
    
    Попытка
    
    НомерНаПечать = Строка(Число(Номер));
    
    Возврат НомерНаПечать;
    
    Исключение
    //Если СтрДлина > 0 Тогда
    Номер = Прав(номер,СтрДлина(Номер)-1);
    //  Иначе
    //   Возврат 0;
    //    конецЕсли;
    
    //  Продолжить;
    
    КонецПопытки;
    
    КонецЦикла;
    
    Возврат  «______________»;
    
    КонецФункции

    Показать

    Reply
  29. v3rter

    (27) Ovrfox, а так?

    НомерНаПечать = Строка(Цел(Число(Номер)));
    Reply
  30. vadim1011985

    (29) v3rter, так вернет 24.

    Ovrfox прав , нужно заменять «.» и «,» то есть знаки которые могу повлиять на формирование числа

    Reply
  31. v3rter

    Получаются два основных подхода:

    1. число справа

    2. все нецифровые символы удаляются, оставшиеся цифровые склеиваются

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

    Reply
  32. dakork

    Попробуйте типовой механизм (БП 3.0) ПрефиксацияОбъектовКлиентСервер.ПолучитьНомерНаПечать(НомерОбъекта, УдалитьПрефиксИнформационнойБазы, УдалитьПользовательскийПрефикс) По умолчанию УдалитьПрефиксИнформационнойБазы = Ложь, УдалитьПользовательскийПрефикс = Ложь

    Reply
  33. lda0312

    НомерБезПрефикса = Объект.ВходящийНомер;

    Пока Найти(НомерБезПрефикса,»0″) <> 1 Цикл

    НомерБезПрефикса = Сред(НомерБезПрефикса,2); //удаляет лидирующие ненули

    КонецЦикла;

    Опасный код. Если в номере не будет нуля то попадаешь в вечный цикл.

    Reply
  34. user633533_encantado

    Статья ради статьи: как пользоваться функцией «Найти», которая , кстати, устарела.

    Reply
  35. Simonov_NPM

    Пока Лев(Номер, 1)=»0″ Цикл

    Номер = Сред(Номер, 2);

    КонецЦикла;

    Reply
  36. user679305_admn.nns

    Мой вариант:

    Функция УдалитьЛидирующиеНули(Знач Номер)

    Пока Лев(Номер,1) = «0» Цикл

    Длина = СтрДлина(Номер);

    Номер = Прав(Номер,Длина-1);

    КонецЦикла;

    Возврат Номер;

    КонецФункции

    Reply
  37. user679305_admn.nns

    Если длина префикса известна, а во всех стандартных конфигурациях она равна 5, тогда

    Функция УдалитьПрефикс(Знач Номер)

    Длина = СтрДлина(Номер);

    Номер = Прав(Номер,Длина-ДлинаПрефикса);

    Возврат Номер;

    КонецФункции

    Reply

Leave a Comment

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