Замена любых символов в любом справочнике




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

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

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

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

42 Comments

  1. dobraleks

    а для 77 есть что-то похожее??

    Reply ↓
  2. CheBurator

    (1) по уму д.б. настраиваемя обработка для удаления из любых строковых реквизитов определенного настраиваемого набора «символов», как-то : табцляции, переводов строк и прочего — что напрочь ломает выгрузку/загрузку в XML и прчие неприятности делает…

    Reply ↓
  3. artbear

    Есть претензии к реализации 🙁

    1. Нафига нужна переменная Отказ?

    представь, что у тебя глюк/отказ на первом же элементе?

    у тебя в транзакции сначала обработаются все элементы, а потом все равно будет отмена этой транзакции.

    После Отказ = Истина сделай Прервать

    2. не видно, по какой причине элемент может быть не записан, т.е. по какой причине выдано исключение 🙁

    3. у тебя будут обрабатываться/изменяться все элементы, независимо от наличия у них нужного сочетания пробелов.

    Совсем не гуд.

    Ведь в запросе можно сразу выбрать только те элементы, у которых в выбранном поле есть более 2-х пробелов.

    В общем, до исправления вышеперечисленного минусую.

    Reply ↓
  4. a-novoselov

    (1) Для 77 реализовать такой алгоритм не получится, т.к. в ней нет оператора Выполнить()

    (2) Если осуществлялся переход с другой системы учета, которая уже не используется, то обмен не нужен. При распределенной базе данных, поменяв данные на главном узле, изменения расползутся по всем базам.

    Reply ↓
  5. artbear

    (3+) 4. Нафига нужен код

    Ссылка = Справочники[Справочник].НайтиПоКоду(1);

    он все равно подходит не для всех справочников 🙁

    юзай

    Ссылка = Справочники[Справочник].ПустаяСсылка();

    Reply ↓
  6. artbear

    (4) «Для 77 реализовать такой алгоритм не получится, т.к. в ней нет оператора Выполнить()»

    вот с чего ты это взял? там есть штатный метод Шаблон, + в ВК 1С++ есть мощнейшний объект ВыполняемыйМодуль.

    Reply ↓
  7. artbear

    (3+) 5. Также я посоветовал бы код

    СписокВыбора.Добавить(МетаСправочник.Имя, МетаСправочник.Синоним);

    исправить на следующий

    СписокВыбора.Добавить(МетаСправочник.Имя, СокрЛП(МетаСправочник.Синоним) +»( «+МетаСправочник.Имя+» )»);

    Т.к. в некоторых конфигурациях синоним не всегда «совпадает» с именем, и это далеко не редкость 🙁

    Будет чуть удобнее 🙂

    Reply ↓
  8. a-novoselov

    (3) (5) (7) Спасибо большое! все поправил 🙂

    (6) я имел ввиду именно такой алгоритм. А вообще, я всех тонкостей 77 не знаю, т.к. 1С начинал изучать сразу с 8.1

    Reply ↓
  9. artbear

    (8) зря ты исправил порядок замены пробелов.

    Раньше, когда сначала 3 пробела менялись на один, а потом 2, было правильно.

    А сейчас наоборот и это неверно.

    Например, стоит 3 пробела, у тебя сначала заменятся 2 пробела, и останется также 2 пробела, которые уже не будут заменены 🙁

    Reply ↓
  10. artbear

    (8) 1. Я бы код

     |Объект = Выборка.Ссылка.ПолучитьОбъект();
    |Объект.[Реквизит] = СтрЗаменить(Объект.[Реквизит], «»  «», «» «»);
    |Объект.[Реквизит] = СтрЗаменить(Объект.[Реквизит], «»  «», «» «»); // Если есть тройные или четверные пробелы
    |Сообщить(«»Заменили «»+Объект.[Реквизит]);
    

    заменил бы на немного другой, без обращения к реквизиту через объект, а через спец.переменную значениеРеквизита, которая заполняется из Выборка.Реквизит, а перед записью

    Объект.[Реквизит] = значениеРеквизита;

    2. сообщение о замене совсем не актуально и наверняка не очень нужно.

    ИМХО удобнее просто вывести количество заменяемых элементов 🙂

    Reply ↓
  11. artbear

    В (9) был неправ 🙂

    забыл, что ты исправляешь пробелы от 2 до 4 включительно, большее количество пробелов не будет исправлено, хотя такое их количество большая редкость, конечно.

    наверное, это также не гуд 🙂

    Reply ↓
  12. MRAK

    На ИТС есть Универсальный поиск и обработка объектов. в ней в режиме 1С-Предприятие прикручиваешь свой код, который пишется за 5 минут (СтрЗаменить) — и вуаля!!!

    Щасте!!!!

    Reply ↓
  13. alexk-is

    (12) Да, все правильно. Только не все могут написать код. И на портале не только программисты…

    Reply ↓
  14. artbear

    (0) Ты по (10) исправил?

    Reply ↓
  15. a-novoselov

    (14) Да, все исправил.

    Reply ↓
  16. artbear

    Минус убрал.

    Reply ↓
  17. werter

    Таб=СоздатьОбъект(«ТаблицаЗначений»);

    Таб.НоваяКолонка(«Номенклатура»,»Справочник.Номенклатура»);

    Таб.НоваяКолонка(«НовоеНазвание»,2,200);

    Тов=СоздатьОбъект(«Справочник.Номенклатура»);

    Тов.ВыбратьЭлементы();

    Пока Тов.ПолучитьЭлемент()=1 Цикл

    Нашли=0;

    Название=Тов.Наименование;

    Пока Найти(Название,» «)>0 Цикл

    Нашли=1;

    Название=СтрЗаменить(Название,» «,» «);

    КонецЦикла;

    Если Нашли=1 Тогда

    Таб.НоваяСтрока();

    Таб.Номенклатура=Тов.ТекущийЭлемент();

    Таб.НовоеНазвание=Название;

    КонецЕсли;

    КонецЦикла;

    Таб.ВыбратьСтроки();

    Пока Таб.ПолучитьСтроку()=1 Цикл

    Тов.НайтиЭлемент(Таб.Номенклатура);

    Тов.Наименование=Таб.НовоеНазвание;

    Тов.Записать();

    КонецЦикла;

    Reply ↓
  18. a-novoselov

    (17) Да, ты прав, так все будет работать. А вот как сделать, если мы не знаем ни названия справочника, ни названия реквизита на этапе кодинга?

    Reply ↓
  19. alteregoatg

    Скачал… работает, но не совсем корректно… пробовал для справочника Номенклатура… во-первых, может обрабатывать только Полное наименование, а Наименование почему-то нет… во-вторых, как я понял, убирать заданное количество пробелов, т.е. если есть 5 пробелов, то за один прогон обработка уберет 2 или 3 пробела, следовательно, обработку надо запускать несколько раз…

    Reply ↓
  20. v.l.

    (0) Предлагаю дополнить функционал — убивать лидирующие пробелы.

    Reply ↓
  21. alexqc

    (18) В смысле — как в 77 по символьному имени обращаться?

    Спр=СоздатьОбъект(«Справочник.» + имяСправочника);

    ЗНРекв=Спр.ПолучитьАтрибут(имяРеквизита);

    Спр.УстановитьАтрибут(имяРеквизита,ЗНРекв);

    Для ТЗ — ПолучитьЗначение/УстановитьЗначение. Подробнее см. синтакс-помошник.

    Reply ↓
  22. a-novoselov

    (2) (19) (20) Реализовал все (или почти все) ваши предложения. Спасибо.

    Reply ↓
  23. alexk-is

    (22) Ну, если все так, то обрати еще внимание на оформление. Где картинка для анонса? Проверь, обработка точно будет под 8.0 и 8.2. Как это заявлено?

    Вот примеры публикаций с неплохим оформлением

    http://infostart.ru/public/62722/

    http://infostart.ru/public/16630/

    Reply ↓
  24. CheBurator

    (18) в 8-ке не знаю, а 7.7 методами рвстроенного языка можно получать перечень всех справочников, документов, их реквизитов, типов и длин реквизитов и т.д.

    Метаданные.Справчочник(счетчик1).Реквизит(счетчик2).Тип или .Длина

    Reply ↓
  25. alexk-is

    (24) В 8-ке почти так же…

    Reply ↓
  26. a-novoselov

    (23) Да какраз после н.г. оформить хотел… на 8.0 работает, 8.2 дистрибутива пока нет, но должна работать. Насколько я понял в 1С работа с метаданными со времен 7.7 почти не изменилась.

    Reply ↓
  27. alexk-is

    (26) Да, «почти»… 🙂

    Reply ↓
  28. Збянтэжаны Саўка

    (4) «Для 77 реализовать такой алгоритм не получится, т.к. в ней нет оператора Выполнить()»

    А зачем через Выполнить()?

    Можно выбросить присвоение ТекстКода и писать сразу код.

    И еще надо проверять на модифицированность объекта чтобы не делать лишних телодвижений:

    СтароеЗначениеРеквизита = Выборка[Реквизит]; //+

    ЗначениеРеквизита = Выборка[Реквизит];

    …

    Объект[Реквизит] = ЗначениеРеквизита;

    Если Объект.Модифицированность() Тогда //+

    Счетчик = Счетчик + 1;

    Попытка

    Объект.Записать();

    // Показать что именно изменили

    Сообщить(Объект.Код + «: Изменен реквизит » + Реквизит + » с <» + СтароеЗначениеРеквизита + «> на <» + ЗначениеРеквизита + «>»);

    Исключение

    Сообщить(«Не могу записать элемент » + Объект.Код + » по причине: » + ОписаниеОшибки());

    Счетчик = Счетчик — 1;

    КонецПопытки;

    КонецЕсли;

    И еще в процедуре СправочникПриИзменении

    маленькое удобство добавить, сразу же и присвоить первый элемент реквизиту, на одно движение меньше:

    …

    ЭлементыФормы.Реквизит.СписокВыбора = СписокВыбора;

    ЭлементыФормы.Реквизит.Значение = СписокВыбора[0]; //+

    Reply ↓
  29. dolter

    (4) у 7.7 нет Выполнить(), но есть Шаблон() 🙂

    Reply ↓
  30. a-novoselov

    (28) Спасибо, добавил.

    Reply ↓
  31. laspii

    Не обрабатывает двойные кавычки, например 3,5″ поменять на 3.5″.

    Доработал:

    в функции Выборка, где встречается СтрокаСимволов.Символ

    СтрокаПоиска = СТрЗаменить(СтрокаСимволов.Символ,»»»»,»»»»»»);

    Reply ↓
  32. gineich

    крутая вещь !!! респект

    Reply ↓
  33. serg85

    Спасибо за обработку, тема актуальна…

    Reply ↓
  34. YuryKr

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

    Reply ↓
  35. Deniz200

    Обработка полезна, но пока скачать и посмотреть не могу. Чем она отличается от поиска и замены значений?

    Reply ↓
  36. a-novoselov

    (35) Отличается тем, что ей может пользоваться простой пользователь, не программист, для конкретной задачи. Дописывать ничего не придется.

    Reply ↓
  37. sdh

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

    я не знаю, как в 1с, возможно ли, но я такой алгоритм писал на SQL. все делается за один цикл. убирается/меняется двойной пробел » » на одинарный » » в цикле, пока находится двойной пробел. что то типа такого:

    WHILE POS (str, » «) > 0 BEGIN

    REPLACE(str, » «, » «)

    END

    при таком алгоритме гарантированно все лишние пробелы убираются и сокращаются до разрешенного одного. пробелы в начале и конце строки обрабатываются обрезанием (если нужно)

    Reply ↓
  38. a-novoselov

    (37) Да, алгоритм тут до боли простой. Но эта разработка была моим дебютом на Инфостарте))

    Reply ↓
  39. Ardl

    Обработка действительно полезная!Пожалуйста, рассмотрите возможность фильтрации (отбора) внутри справочника. т.е. изменить какое-либо значение в справочнике при отборе по конкретному: коментарию, НДС, другим полям как номенклатурной катрочки, так и других справочников. Надеюсь идею смог донести!

    Reply ↓
  40. a-novoselov

    (39) Да, идею донести смогли, но пока времени нет заниматься этим, если будет свободное время — сделаю. Или можете сами (если есть желание) доработать / выложить со ссылкой на исходник.

    Reply ↓
  41. Ardl

    Желание есть, но знаний не хватает! Буду смиренно ждать вашего релиза, в любом случае спасибо за оперативный ответ и обработку!

    Reply ↓
  42. motya-98@list.ru

    Добрый вечер.

    Не найдется ли файл RENUMBER.ERT для 7

    Благодарю.

    Reply ↓

Leave a Comment

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