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




Принцип обмена данными из 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='\

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 не будет опубликован. Обязательные поля помечены *