Остатки товаров с группировками




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

25 Comments

  1. CheBurator

    Ну ща…!

    1.

    > Если З.Выполнить(ТЗ)=0 Тогда

    {H:\_НАКОПИТЕЛЬОТЧЕТОВ.DIROSTОСТАТКИ ТОВАРОВ ДЛЯ ТОРГОВЛИ.ERT(123)}: Невозможно обращение к итогам после ТА

    Какая-то ошибка в запросе!

    Типовая ошибка определения конечной даты отчета…

    2. В качестве группы дается возможность выбора конкретной позиции = это так задумано…?

    3. Выводить в ячейках отчета рассчтываемые значения — это гуд? для целей увеличения скорости формирования? И как это потом скажется на сохранении в эксель.. м.б….?

    4. Комментарии отсутствуют как класс

    4а. Где множественный фильтр? елы-палы…?!

    5. работает быстрее встроенного какого? и насколько? особенно хотелось бы узнать — за счет чего?

    6. особенно порадовала конструкция

    ТЗ=»//{{ЗАПРОС(Сформировать)

    |Период с ДатаДок по ДатаДок;

    |Обрабатывать НеПомеченныеНаУдаление;

    в применении к регистру

    |Склад = Регистр.ОстаткиТМЦ.Склад;

    |Фирма = Регистр.ОстаткиТМЦ.Фирма;

    |УпрАналитика = Регистр.ОстаткиТМЦ.Фирма.УпрАналитика;

    |ЮрЛицо = Регистр.ОстаткиТМЦ.Фирма.ЮрЛицо;

    7. опфть же конструкция, которая идет далее:

    |Группировка Номенклатура Без Групп;

    |Группировка Цена;

    |Группировка Вес;

    деление по продажным ценам внутри номенклатуры для розничного склада я еще понимаю…, но для оптового? в запросе это никак не фиксируется… зачем гонять «лишнюю» группировку в запросе, если жто не надо?

    Чего я не понял — это группировка по весу внутри продажных цен….? хотя, не скинем со счетов, что я просто не догнал..

    8. Порадовала конструкция

    КК=40;

    ККК=0;

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

    ККК=ККК+1;

    Если ККК>=КК Тогда

    Состояние(«ШАГ 1. Обработано «+ККК+» из «+Таб.КоличествоСтрок()+» …»);

    КК=КК+40;

    КонецЕсли;

    ..

    видимо проги не знают про операцию А%Б

    итого вкратце:

    — предоставляет расширенные возможности формирования остатков — очень сомнительно

    — И вообще, наш отчет работает быстрее встроенного в 1С и является прекрасной иллюстрацией стиля и методов программирования — голословное заявление без должного обоснования — ну, я думаю, в свете озвученного выше — комментировать не будем… каждый выводы сам сделает…

    итого: вполне прокатит как учебное пособие для новичков или шаблон для создания своего

    Reply
  2. O-Planet

    Ну не злодей ли, а?

    Хоть бы по делу что написал…

    1. Про ТА — молчу. Нормальный чел к дате после ТА не обращается.

    2. > В качестве группы дается возможность выбора конкретной позиции = это так задумано…?

    — ДА

    3. > Выводить в ячейках отчета рассчтываемые значения — это гуд?

    А ты так смогешь? Ведь работает и быстро однако.

    4. > Комментарии отсутствуют как класс

    А они кому нужны?

    4а. > Где множественный фильтр? елы-палы…?!

    Исжил себя, как класс. Ты чо хочешь ентим фильтром фильтровать?

    ДЛЯ ОСОБО ОДАРЕННЫХ: Просто щелкни мышью прям в печатной форме по серому заголовку «Код» али «Номенклатура» али «Артикул» . Смотри, что будет. Только сиди, что бы не упасть…

    5. > работает быстрее встроенного какого?

    Аналогичного по товарам, очевидно. (С твоим любимым множественным фильтром)

    > и насколько?

    Ну посчетай

    > особенно хотелось бы узнать — за счет чего?

    А вот и не скажу!

    > 6. особенно порадовала конструкция …

    Ты верно с базами под SQL не сталкивался, да со справочником товаров в 30000 позиций… Тогда бы понял, почему я к регистру из запроса обращаюсь…

    А «Период с ДатаДок по ДатаДок» — это на уровне рефлекса. Учили нас в МГУ перестраховываться, когда программы пишешь.

    7. > опфть же конструкция, которая идет далее …

    > хотя, не скинем со счетов, что я просто не догнал

    Ты действительно, не догнал.

    8. … видимо проги не знают про операцию А%Б

    ГЫ! Это можно оставить без комментариев, предложив каждому самому решать, какую операцию в цикле предпочтительнее выполнять: сложение или деление. (Кстати, это маленькая подсказка на вопрос 5 за счет чего) Ты так свои мудрые программы пишешь? Втыкаешь куда не поподя разные операторы, которые выглядят кратко, а на деле работают раз в 200 дольше? Да, видимо слова «ассемблер» и «регистр» для некоторых звучит, как «динозавр». А зря! Я чо делаю своей конструкцией? В цикле проверяю в регистре флаг «отрицательно». Это одна операция для процессора, несколько наносекунд. Ты же своим А%В проц грузишь по полной. Впрочем, это секретные технологии, знать которые дано не каждому.

    Да, чебурашка. В следующий раз, когда будешь писать коммент на творение программистов, типа меня, употребляй слово «Прог» с большой буквы. Не скучай.

    РЕЗЮМЕ. Работает, как и заявлено.

    Reply
  3. CheBurator

    1. Нормальному юзеру, юзающему отчет — нафиг знать дата после ТА или ДО. Итого — ответ не в тему.

    2. Согласен.

    3. Да не вопрос, работает — и ок.

    4. ну, в принципе, для такого шаблона — не нужны.. это точно…

    4а. Те же самые свойства товаров… из обсуждения в другом топике 😉

    Для особо одаренных: ну и что? это сразу было понятно/видно…

    В чем цимус-то? недогоняю… 😉

    5. Не будем уточнять за счет чего, ок. Утверждение осталось голословным.

    6. Для особо отдаренных: читай описание конструкции «обрабатывать…» и jmkfcnm ее применения, потом — учи программировать других 😉

    7. Не вопрос, согласен.. 😉

    8. Аргументированное обсуждение будет продолжено позже… 😉

    Ну, до Прога ты еще не дорос, это точно.. 😉

    То что работает — я и не обсуждал, работает и ок.

    Тока это не творение Прога, как это пытаются представить… 😉

    Reply
  4. aaa

    В программах на встроееном языке при формировании товарных остатков ловить наносекунды за счет ясности — это ошибочное заблуждение. Смешно даже обсуждать такие навороты с KK = 40. Я полностью разделяю комментарии Che Burashка

    Reply
  5. CheBurator

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

    Предварительно, конечно выкинем из цикла такую безумную конструкцию как получение количества строк ТЗ в цикле — наглядная иллюстрация принципа «не надо делать много ошибок в программе — достаточно сделать одну и обращаться к ней в цикле». и проведем сравнение

    На цикле из 50 тыс. с шагом в 87 прогоним вариант 1

    //*******************************************

    Процедура Сформировать1()

    КК=Шаг;

    ККК=0;

    сч = 0;

    Время1 = _GetPerformanceCounter();

    Для сч=1 По Граница Цикл

    ККК=ККК+1;

    Если ККК>=КК Тогда

    //Состояние(«ШАГ 1. Обработано «+ККК+» из «+Граница+» …»);

    КК=КК+Шаг;

    КонецЕсли;

    КонецЦикла;

    Сообщить(«вар.1, «+Граница+» по «+Шаг+» затрачено: «+(_GetPerformanceCounter()-Время1)/1000);

    КонецПроцедуры

    ..

    и вариант2

    //*******************************************

    Процедура Сформировать2()

    КК=Шаг;

    сч = 0;

    Время1 = _GetPerformanceCounter();

    Для сч=1 По Граница Цикл

    Если сч%КК=0 Тогда

    //Если (сч-КК)=0 Тогда

    //Состояние(«ШАГ 1. Обработано «+сч+» из «+Граница+» …»);

    кк=кк+шаг;

    КонецЕсли;

    КонецЦикла;

    Сообщить(«вар.2, «+Граница+» по «+Шаг+» затрачено: «+(_GetPerformanceCounter()-Время1)/1000);

    КонецПроцедуры



    первый вариант в реднем показывает 0.19 сек, второй — 0.81 сек.

    Разница ощутимая? Несомненно! На что влияет такая разница? Да собственно, говоря — ни на что (единственное, позволяет гордиться принадлежностью к клану настоящего Прога — ну, про ТЗ.КоличествоСтрок() в цикле умолчим…) Для юзера — практически незаметно… Хотя если, конечно, цикл увеличить до 1,5 млн — разница уже будет заметна… и 100 юзеров в терминале юзают только такой адгоритм… тады, да, я признаю свое поражение, облажался… 😉



    Однако первый вариант можно ускорить еще примерно на 10 процентов без особых затрат очень просто: юзать вместо конструкции

    Если ККК>=КК Тогда

    следующую:

    Если (ККК-КК)>=0 Тогда



    Однако, видимо, настоящие Программисты, до которых я еще не дорос, ассемблер пробежали «по верхам» и разницы не уловили… 😉

    ладно, что-то я ваще злобствовать начал 😉

    А по поводу высказанного ААА — присоединяюсь.

    Reply
  6. O-Planet

    Сразу видно настоящего рыцаря мыши, умеющего с легким сердцем относиться к поражению. 🙂 Но поражение — действительно, более теоретическое. Мало таких баз данных, где преимущество метода проявится в полной мере. Что делать, учили когда-то, что всегда надо стараться избегать операций * и /. (А было это еще тогда, когда по сравнению с MERA — Masovia считалась супер компьютером, а IBM086 — вообще, компьютером будущего) Кстати, вы на какой компе все это тестили? Чай на пне четвертом? Попробуйте ка все то же самое прогнать на Celeron 733 с оперативкой в 64 мб… (Так что ААА — пролетает)

    По поводу ТЗ.КоличествоСтрок() — это от лени, конеечно. Этот отчет прям у клиента писался за два часа, особо вылизывать не приходилось

    А ассемблер я действительно, по верхам просматривал, улавливая лишь суть. Он никогда не был моей специализацией. Кстати, я знаю, что хорошие трансляторы, типа Borland, конструкции А0 🙂 Мож, 1С относится к их числу? Хотя… Если кто ради интереса смотрел, как она отрабатывает выражение, типа —

    Попытка

    Если (12)и(1/0>0) Тогда

    Сообщить(«Хороший транслятор!»);

    КонецЕсли;

    Исключение

    Сообщить(«Дура, блин!»);

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

    — то спрашивать об этом не будет…

    Reply
  7. O-Planet

    Сразу видно настоящего рыцаря мыши, умеющего с легким сердцем относиться к поражению. 🙂 Но поражение — действительно, более теоретическое. Мало таких баз данных, где преимущество метода проявится в полной мере. Что делать, учили когда-то, что всегда надо стараться избегать операций * и /. (А было это еще тогда, когда по сравнению с MERA — Masovia считалась супер компьютером, а IBM086 — вообще, компьютером будущего) Кстати, вы на какой компе все это тестили? Чай на пне четвертом? Попробуйте ка все то же самое прогнать на Celeron 733 с оперативкой в 64 мб… (Так что ААА — пролетает)

    По поводу ТЗ.КоличествоСтрок() — это от лени, конеечно. Этот отчет прям у клиента писался за два часа, особо вылизывать не приходилось

    А ассемблер я действительно, по верхам просматривал, улавливая лишь суть. Он никогда не был моей специализацией. Кстати, я знаю, что хорошие трансляторы, типа Borland, конструкции А больше В сами заменяют на (А-B) больше 0 🙂 Мож, 1С относится к их числу? Хотя… Если кто ради интереса смотрел, как она отрабатывает выражение, типа —

    //**************************

    Попытка

    Если (2>1)и(1/0>0) Тогда

    Сообщить(«Хороший транслятор!»);

    КонецЕсли;

    Исключение

    Сообщить(«Дура, блин!»);

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

    //**************************

    — то спрашивать об этом не будет…

    Reply
  8. Это не поражение, это ближе к ничьей… 😉

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

    Тестил на Атлоне 1800+, 512 Мб

    Reply
  9. O-Planet

    > Тестил на Атлоне 1800+, 512 Мб

    А…

    > На быстрой — работает — ну и ок, а на медленной — надо смотреть…

    Не знаю. На медленной не работать может как раз из-за неоптимальности. Нет, ААА не прав только потому, что назвал безобидный счетчик-ползун в три строки «наворотами». Проблема то в чем? Если прог нормальный, то ему — по барабану, что там будет стоять А%В или А>В — суть -то одна, и она должна быть понятна с первого взгляда. А каких «наворотах» речь-то?

    Reply
  10. CheBurator

    Речь не о наворотах, а о понятности и аккуратности кода.

    Не привязываясь к данному КК — согласись, что код обработки далек от читабельности, хотя конечно от бесплатной разработки требовать «красоты» — не все же пишут красиво забесплатно.

    Reply
  11. O-Planet

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

    Reply
  12. O-Planet

    Вот такой счетчик будет уже ближе к наворотам 🙂

    //******************************************* (в глобальнике)

    Процедура Линейка(К,КК,Шаг) Экспорт

    Если (К>=КК)и(Шаг>0) Тогда

    Зв=КК/Шаг;

    Стр1=»##############################»;

    Стр2=»~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~»;

    Состояние(Лев(Стр1,Зв)+Сред(Стр2,Зв+1));

    КК=КК+Шаг

    КонецЕсли;

    КонецПроцедуры //Линейка

    // В какой-нить процедуре …



    Шаг=Окр(Табл.КоличествоСтрок()/30,0,1);

    КК=Шаг;

    Для К=1 По Табл.КоличествоСтрок() Цикл

    Линейка(К,КК,Шаг);



    КонецЦикла;

    //*******************************************

    Reply
  13. aaa

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

    Если уж мне надо быстродействие, я напишу на прямых запросах и ваш % отдыхает. И какая доля % в общем времени отчета?

    Может я и неправ, но я предпочитаю ясный и понятный код, чтобы не сидеть через месяц (а не дай бог через года 3, бывало) и не думать, что же я вообще хотел тут сделать

    Reply
  14. aaa

    И когда я вижу идентификаторы типа «КК» и конструкции КК=40 (а почему не 43?:)) мне плохо становится, не знаю почему:)) Рефлекс такой

    Reply
  15. > построен строго по определенному методу, позволяющему делать быстрые отчеты с группировками.

    Не вопрос, согласен в ценности МЕТОДА. пусть это будет ++++++++

    Но категорически не согласен с оформлением программного кода ———-

    Поддерживаю ААА.

    Reply
  16. O-Planet

    > Вы постоянно сами себе противоречите. То утверждается, что обработка-кладезь программисткой и инженерной мысли

    Да, лицо фирмы. Потому что она позволяет ПОЛЬЗОВАТЕЛЮ многое из того, что ему не хватало получать ПРОСТО и БЫСТРО. Если кому-то из программистов не нравится стиль (= не хватает ума разобраться), то юзеру то не пофиг ли, что там внутри? По поводу системности — именно так. Писалось два часа по простой и понятной методике составления подобных отчетов. Возможно, конечно, оно кажется угловатым, если с этой методикой не знаком. Но обладая ей, даже новичок сможет быстро своять коммерческую работу.

    > И когда я вижу идентификаторы типа «КК» и конструкции КК=40 (а почему не 43?:)) мне плохо становится, не знаю почему:)) Рефлекс такой

    Это фобия какая-то? Можно и 43, конечно, это — на любителя.

    > Если уж мне надо быстродействие, я напишу на прямых запросах

    Попробуйте. Прямые запросы не покатят, потому что там постфункции сортировки реализованы, а это — пересчет всякий раз. Я же от него избавился.

    Reply
  17. aaa

    Должно настораживать, что всем вокруг не хватает ума:) это тоже фобия, и покруче нелюбви к КК 🙂

    Reply
  18. CheBurator

    > Но обладая ей, даже новичок сможет быстро своять коммерческую работу.

    Читаем статью про «хорошего программиста», вторая стадия «хорошего программиста» — «продвинутый Прог» 😉

    Reply
  19. O-Planet

    Да ну вас, блин! 🙂

    Reply
  20. AlexKnv

    Нормальный отчет…

    Reply
  21. sys

    отчет хорош, нет выбора с резервами или без

    Reply
  22. evgennnnn

    Выдает ошибку?

    КратРубля = глКратностьДляВалюты<<?>>(глРубли,ДатаДок);

    {C:DOCUMENTS AND SETTINGSADMINРАБОЧИЙ СТОЛЗАГРУЗКИОСТАТКИ ТОВАРОВ ДЛЯ ТОРГОВЛИ.ERT(130)}: Функция не обнаружена (глКратностьДляВалюты)

    Ц=глПересчет(Ц,Вал,ДатаДок,глРубли,КурсРубля,<<?>>Вал.Кратность,КратРубля);

    {C:DOCUMENTS AND SETTINGSADMINРАБОЧИЙ СТОЛЗАГРУЗКИОСТАТКИ ТОВАРОВ ДЛЯ ТОРГОВЛИ.ERT(158)}: Слишком много фактических параметров

    Сумма=глПересчет(Сумма,Вал,ДатаДок,глРубли,КурсРубля,<<?>>Вал.Кратность,КратРубля);

    {C:DOCUMENTS AND SETTINGSADMINРАБОЧИЙ СТОЛЗАГРУЗКИОСТАТКИ ТОВАРОВ ДЛЯ ТОРГОВЛИ.ERT(159)}: Слишком много фактических параметров

    Reply
  23. O-Planet

    (22) Просто у Вас старая конфигурация торговли.

    Reply
  24. evgennnnn

    посоветуйте как обновить?до какого релиза?

    Reply
  25. A.Belash

    Считается реально быстро, +

    Reply

Leave a Comment

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