Загрузка прайс-листов поставщиков/конкурентов




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

22 Comments

  1. CheBurator

    (+) Потому как идея правильная. Свою более функциональную не выкладываю — жаба, сволочь, душит. Но взяв за основу эту + нечеткое сравнение строк — можно хороший комплекс сваять…

    Reply
  2. &-rey

    а нечеткое сравнение строк — вторая обработка (отдельная) — и используется для добавления позиций в аналоге (чтобы не ручками) : во-первых при нечетком сравнении прайс грузиться сутки будет, во вторых — можно закачку доверить «девочке» которая сама выбирать «похожее» (с ее точки зрения) не будет. Ведь могут быть тонкости типа BOX/OEM/RET или буква гдето или интерфейс немного другой но таже модель — цена соответственно может отличаться существенно — ведь товар то другой!

    Reply
  3. CheBurator

    Сутки не будет. У меня примерно 10000 позиций в авторежиме идентифицируется примерно минут 20.. А потом иерархическая процедура проверки правильности идентификации =- у меня целая методика есть, успешно работает… А с накоплением прайсов и аналогов точность автопривязки новых прайсов можно довести почти до 100% — сравнивать не только со своей номенклатурой, но и с уже привязанными аналогами.. ну дальше понятно… Чувствую, надо скриншотов наделать и выложить на оборзение народа — мож кому и интересно будет…

    Если с умом подойти

    Reply
  4. CheBurator

    «Родственная разработка» для иллюстрации нечеткого сравнения

    http://infostart.ru/projects/index.php?id=393&order=date&ref=174

    Если к твоей загрузке прикрутить выбор «нечеткой» позиции (как у меня в разработке) — будет уже пучково! — может кому и пригодится…

    Reply
  5. Ну прям то что давно ищу! Спасибо, очень пригодилось!!!

    Reply
  6. elder

    У меня при запуске выдает следующее:

    Если ПустоеЗначение(Константа.ВидСвойстваНоменклатуры) = 0 Тогда

    {C:PROGRAM FILES1CV77EXTFORMSИМПОРТПРАЙСЛИСТОВ.ERT(83)}: Поле агрегатного объекта не обнаружено (ВидСвойстваНоменклатуры)

    Reply
  7. Khaliff

    для загрузки прайса поставщика — нужен ли код товара?

    если да, то обработка мне не подойдет, т.к. поставщики публикуют с кодом

    Reply
  8. Khaliff

    т.е. не публикуют

    Reply
  9. CheBurator

    (8) крайне желетелден некий ОДНОЗНАЧНЫЙ ИД, идентифицирующий данную позицию по «списку» поставщика; это может быть:

    — код по базе поставщика;

    — артикул товара по базе поставщика;

    — шк товара (еан или иной однозначно определяющий);

    — некий ИД самого товара (например типа микросхема однозначно определяется макрикровкой на корпусе);

    .. в случае отсутствия такого ИДа в его качестве используем наименование товара (+производитель), переведенное НОРМАЛИЗАЦИЯНЕЗНАЧАЩИХСИМВОЛОВ(СОКРЛП(ВРЕГ()))

    Reply
  10. Khaliff

    (9) этот код должен быть одинаковым у поставщика и у меня?

    предположим я у себя в базе запомню какой код у поставщика_1

    для каждого моего товара…

    а дальше придет прайс от поставщика_2 с его кодами товаров,

    а у меня 1С-ка уже запомнила другие коды,

    как я загружу прайс_2?

    Reply
  11. CheBurator

    Включаем мозги!

    У каждого прайса есть «хозяин».

    если хозяин = неизвестный, то какая ценность от такого прайса?

    Соответсвенно, запоминая прайс поставщика — мы однозначно идентифицируем его (сам прайс) неким удобным нам образом, например? указываем, кто является хозяином прайса.

    Reply
  12. &-rey

    Все просто!) У каждой номенклатуры есть подчиненный справочник Аналоги. В нем есть Наименование — тут название этой номенклатуры в том виде, в каком он виден в прайсе поставщика, Каталог Аналога — тут как раз привязка к конкретному поставщику, как сказал Сhe Burashka — «хозяин» прайса. Ну назовите его например «Каталог Поставщика 1», и есть идентификатор в каталоге — это артикул или ID номер товара в прайсе данного поставщика. Таким образом, для каждого товара вы создаете кучу аналогов по каждому закачиваемогу прайсу, ну и вперед, качаем прайсы…

    На январские каникулы думаю переносить все наработки на восьмерку…бррр…давно решались перейти, да как подумаешь скока лопатить……..

    Reply
  13. ljuter

    Как обстоят дела с переводом на восьмерку?

    Reply
  14. &-rey

    На восьмерке все еще не реализовано, но там возможности шире и поэтому получается более интересное решение. Правда еще на заброшенной стадии в связи с тем что сами на восьмерку не успели перейти. Скорее всего к началу года будет сделано для перехода работы на восьмерке

    Reply
  15. ljuter

    К началу следующего года?

    Это будет платное решение?

    Будет отдельная конфа?

    Reply
  16. ljuter

    Пишу небольшую похожую разработку. Как сгенерировать уникальный артикул товара (не во всех прайсах есть артикул)?

    Reply
  17. CheBurator

    выбираем перечень полей из прайса поставщика, которые будут «составлять» уникальный ИД. На примере лекарств таким ИДом будет являться ИД=Наименование+Производитель, Полученный ИД «нормализуем»:

    1. выкидывем все символы из данного списка — <пробел>.,;’*/?!#$@» ну и прочее подобное

    2. переводим все в верхний регистр

    ОПА! — вот он, ИД!

    я еще наименование и производителя разделяю спецсимволом типа 0135 — чтоб если что вытащить…

    Reply
  18. ljuter

    Не понял. Если у меня в названии товара 35 символов + 7 символов название производителя то ИД будет 42 символа? Нужно чтобы арикул содержал 7 символов, вне зависимости от названия товара и производителя.

    Reply
  19. ljuter

    К предыдущему сообщению: нужно реализовать в версии 8.0 (8.1)

    Reply
  20. &-rey

    Если наконец дойдут руки и сделаю наконец под восьмерку, то выложу, я сторонник свободного ПО))) Так что — не жалко, только бы время найти… Из-за времени и не перешли в этом году на восьмерку. Хотя на восьмерке получается гораздо удобнее и нагляднее загрузка. В ней я решил идти «от обратного» — Если раньше искал в своем товаре совпадения с загружаемыми, то теперь наоборот — весь прайс загружается в справочник «Номенклатура контрагентов» а потом идет поиск совпадений по новым алгоритмам и в наглядном виде появляется таблица соответствий. Затем в интерактивном режиме можно добавить соответствия, которые тут же запоминаются и заливаются цены… Мне это больше понравилось. Но доделать некогда.

    А по поводу прайсов без артикула — правильно сказал Чебур{Здарова, давненько чет не заходил я сюда} )) Хотя я поступаю проще… В семерке например есть в справочнике «Аналог» и Наименование и Артикул. Так кто же мешает искать совпадение либо по артикулу либо по полному наименованию? Ну а в случае с «колесами» объеденить наименование и производителя в одну строку и добавить в аналог…

    Reply
  21. CheBurator

    (18) можешь сгенерить и уникальный артикул для позиции поставщика — что с ним дальше делать будешь? этот артикул все равно придется привязывать к позиции поставщика… читай (20) последний абзац

    Reply
  22. ljuter

    Ясно, спасибо за разъяснения. А какие на сегодняшний момент есть бесплатные загрузчики прайсов с аналогами (синонимами) номенклатуры? Вкратце: в номенклатуре наименование товаров идентичное с названием у производителя, но поставщики в прайсах пишут кто как хочет )). Без синонимайзера не обойтись.

    Reply

Leave a Comment

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