Прайс-лист в два столбика




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

34 Comments

  1. johnicjs

    Есть небольшие недостатки, но таков был заказ.

    Например, попадает вся номенклатура (даже если помечена на удаление или неустановлена цена). Но это передалать просто.

    ❗ P.S. Кому понравится поставте плюсы.

    Reply
  2. akozhuhova

    При выполнении выдает ошибку, если количество строк, к примеру 10, это нормально? 😮

    Ошибка при вызове метода контекста (Область): Область не найдена: R1C1:R0C5

    ТД1.ВставитьОбласть(ТД2.Область(«R1C1:R»+Строка(Строк-10)+»C5»),Тд1.Область(«R1C7:R»+Строка(Строк-10)+»C11»));

    Reply
  3. johnicjs

    ❗ Спасибо,исправил.

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

    Reply
  4. akozhuhova

    ))) ясно

    Reply
  5. dobraleks

    есть ли возможность сделать 2 столбика для 77??

    Reply
  6. johnicjs

    Написанной у меня нет, так что только заказать 🙁

    Поищите, тут возмозно есть готовая.

    Reply
  7. dobraleks

    😀 вау, какая оперативность на ответ.. (2 минуты и 3 сек 🙂 )

    Reply
  8. johnicjs

    У меня майлагент стоит, инфостарт оповещение сразу присылает 😀

    Reply
  9. Арчибальд

    (5) Да хоть три 🙂

    Reply
  10. MRAK

    (9) да вопрошающий в 5 хотел уже готовую…

    Reply
  11. Berrimor

    (5) есть готовое, но хитро заточенное под переделанную ТИС, есть интерес обсудим

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

    Reply
  12. spy-83

    (5) Есть готовая для типовой ТиС

    Reply
  13. johnicjs

    Давайте, хоть тут не будем торговать.

    Reply
  14. coolo

    Интересная реализация, на основании этой делал и на три столбика, Единственное не придумал как реализовать не построчный вывод… а как бы змейкой чтоб шло не слева направо по алфавиту а сверху вниз… ппервый столбик, второй столбик итд

    Reply
  15. rc.d

    Отличная обработка, очень пригодилась! Немного допилил под свои нужды, но в целом прекрасно!

    Reply
  16. johnicjs

    (15) Спасибо, приятно когда ценят работу.

    Reply
  17. rc.d

    Есть вопросец. К сожалению, руки не доходят запилить сортировку. Можете доработать? Например, по коду или артикулу? У нас в прайс-листе такой ахтунг творится, что без сортировки никак.

    Reply
  18. rc.d

    Кроме того, строчный параметр в связке с шапкой прайса создает внушительный косяк при печати. Скрины прилагаю. Строк указано 60.

    Как можно видеть, строка заголовка прыгает по страницам в зависимости от ширины и толщины, что мешает печатать его в таком виде, а алгоритм расчета нужных строк пока не додумал.

    Reply
  19. johnicjs

    (18) Этот прайс был написан очень давно и подгонялся под китайский неизвестный принтер. Там все отрабатывало хорошо.

    Reply
  20. rc.d

    Кстати, никак не могу понять, не так силен в программировании, вот у меня товар есть, а цены к нему нет, хочу поставить вместо пустого поля слово «Заказ», но как я не пытался в вашем коде поменять в ОблСтроки.Параметры.Цена ноль на «Заказ», так ничего и не получилось. Почему так и можно ли подправить?

    ==============================

    Если Не Результат.Количество()=0 Тогда

    Пока Результат.Следующий() Цикл

    //Цену нашли, выводим

    ОблСтроки.Параметры.Цена=Результат.Цена;

    КонецЦикла;

    Иначе

    ОблСтроки.Параметры.Цена=0;

    КонецЕсли;

    ==============================

    Заранее спасибо.

    Reply
  21. johnicjs

    (20), в свойствах макета на эту ячейку стоит, что она содержит тип число и его формат. Если менять, то нужно поставить там тип строка и цену передавать уже отформатированной строкой.

    Reply
  22. rc.d

    Спасибо!

    Reply
  23. johnicjs

    (22) Не за что, если не получится обращайтесь, доработаю. Думаю договоримся.

    Reply
  24. rc.d

    Поменял, все отлично отображает, только теперь копеек нет, но это не проблема, их всё равно нет 🙂 В заголовке написал «Цены с НДС, руб.», думаю народ поймет.

    Теперь другая засада: в вашей обработке построение столбцов делается поочередно Вот у меня 60 страниц прайса, первая половина номенклатуры выстраивается вертикально через весь столбец. То есть идут у меня трубы стальные по артикулу 1010-хххх и идут они у меня и на второй странице, и на третьей, и так далее, а за ними 1020 также ползут и так до 60й, а потом с первой 1080 и так далее. То есть фактически у меня прайс не упорядочен, ибо на одной странице оказываются совершенно разные товары.

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

    Решение видится такое.

    Создать два параметра строк:

    1. Под первую страницу — высчитывать необходимое число строк эмпирическим путем, чтобы пользователь сам определял сколько ему нужно.

    2. Под все остальные — опять же индивидуальным подсчетом.

    При решении сих проблем возникнет другая. Как считать число строк в случаях, когда наименование товара длиннее отведенной ему строки, и строка будет перенесена? А таких строк на каждой странице тучи! А страниц тоже туча! Вот тут голова пока ничего не придумала, разве что ручное запиливание. Надо бы это твопрос внимательней рассмотреть, тогда вашей обработке цены не будет))

    Upd: придумал указывать фиксированно в макете высоту строк равной 20, получается неплохо, теперь остается решить вопрос с количествами строк.

    Reply
  25. johnicjs

    (24),

    1) В ценах отрубаются последние нули, потому нет копеек, нужно ОблСтроки.Параметры.Цена=Результат.Цена; Заменить на ОблСтроки.Параметры.Цена=Формат(Результат.Цена,»ЧЦ=15; ЧДЦ=2″);

    2) Не помню, больше двух лет прошло, а писалось и того раньше, что-то у вас напутано с настройками, 2 столбец должен начинаться с конца текущего листа. Иначе бы заказчик не принял бы обработку.

    3) Динамическая ширина строк не выйдет, т.к. будут накладки если разная ширина в разных столбцах. Да и пиксели считать не самое веселое занятие.

    Еще раз повторюсь, что прайс писался давно и под конкретного заказчика.

    Reply
  26. rc.d

    Да, виноват, уже разобрался, все работает правильно и отлично!

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

    Вижу, что у вас в условиях стоит 11 строка, на которой начинается группа.

    Сдвинул условия на 10 строку, теперь сползает второй столбец, причем только на первой странице. Картинку прилагаю.

    Походу надо менять количество рядов в расчете второго столбца, но так и не понял где на 100й строке значение менять:

    ТД1.ВставитьОбласть(ТД2.Область(«R1C1:R»+Строка(Строк-10)+»C5»),Тд1.Область(«R1C7:R»+Строка(Строк-10)+»C11»));

    Reply
  27. johnicjs

    (26) Все просто, уберите шапку и вывод для первой страницы.

    Reply
  28. rc.d

    А не подскажете, как это сделать? как я уже упоминал, не силен в программировании. Не смог точно определить где заканчивается вывод первой страницы.

    UPD: пока «полечил» тем, что сделал текст в шапке белым, на печать не попадает, уже хорошо.

    И второй более важный для меня вопрос. У нас в прайсе оптовая с ндс цена не хранится в базе, а рассчитывается, при выводе прайса на печать обработка выдает пустые значения, и поэтому я выставляю оптовую. Как сделать так, чтобы цена с ндс посчиталась при выполнении? То есть по факту надо оптовую, которая пришла в обработку, умножить на 1,18.

    Вы уж извините, что так насел, но на курсы по 1С я поеду только через неделю, а решать подобные задачи надо уже сейчас. Заранее спасибо за помощь!

    Reply
  29. ASoft

    Спасибо. Плюсую.

    Reply
  30. rc.d

    Всё, все вопросы решены. Спасибо за помощь!

    Reply
  31. rc.d

    Ан нет, последний вопросец вспомнился. Так сортировку желательно сделать по артикулу, но не знаю как. Обработка граббит коды товаров и прямо подряд их гонит. А как поменять принцип сортировки?

    Reply
  32. johnicjs

    (31), если не изменяет память, то там идет прямой обход справочника. В данном случае, скорее никак, переделать на запрос только.

    Reply
  33. ProGramMoS

    Спасибо все разобрался)))

    Reply
  34. RosT_Dnepr

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

    Заточил под новую версию 1С и немного доработал под себя.

    Автору спасибо, не пришлось писать с нуля))

    Reply

Leave a Comment

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