Полезные процедуры по работе с СКД и табличными документами (часть 1)




Принцип обмена данными из 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. Поручик

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

    Reply
  2. Makushimo

    в копилочку

    Reply
  3. Новиков

    Класс! Спасибо!

    Reply
  4. LexSeIch

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

    Reply
  5. kser87

    Почему вместо этого:

    Маркер = «Бонусы»;
    ОбъединтьЯчейкиВТабличномДокументе(ДокументРезультат, Маркер);

    нельзя использовать Группы полей? А вместо скрытия сумм использовать макеты?

    И еще наблюдение: на больших объемах данных это:

    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
    ПроцессорВывода.УстановитьОбъект(Результат);
    
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);

    Работает значительно медленнее, чем это:

    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
    ПроцессорВывода.УстановитьОбъект(ДеревоРезультат);
    
    ПроцессорВывода.НачатьВывод();
    
    ЭлементРезультат = ПроцессорКомпоновкиДанных.Следующий();
    
    Пока ЭлементРезультат <> Неопределено Цикл
    
    ПроцессорВывода.ВывестиЭлемент(ЭлементРезультат);
    ЭлементРезультат = ПроцессорКомпоновкиДанных.Следующий();
    
    КонецЦикла;
    
    ПроцессорВывода.ЗакончитьВывод();

    Показать

    Reply
  6. Yashazz

    (5) kser87, эхма, почему… да потому что не умеют, видимо, иначе, как курочить готовый моксель. Даже Хрусталёва не впрок, ага.

    Reply
  7. json

    (5) kser87, благодарю за критику.

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

    Первую часть вашего сообщения прокомментирую попунктно:

    1. Скрыть ячейки в шапке через макет — да можно. Конкретно в статье я хотел продемонстрировать использование процедуры по скрытию строки. Для примера была выбрана строка Сумма.

    Предложенный в статье способ можно рассматривать как альтернативу. Кроме того, несколько раз попадались случаи, когда скрыть строку макетом не получалось, например, когда нужно скрыть строку в выводимой таблице (не в шапке)

    2. По поводу использования группы полей для объединения

    а. С помощью группы полей можно объединить только колонки ресурсов, т.е. когда количество колонок задается разработчиком при написании отчета. Если количество колонок динамическое — то при объединении выбранных полей в группу — ячейки не объединяются.

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

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

    Reply
  8. Yashazz

    А автор знает про разные макеты для разных фрагментов данных СКД?

    Reply
  9. json

    (6) Yashazz, (7) Yashazz, в данной статье задачи упрощены для более наглядной демонстрации предлагаемых процедур. Поэтому некорректно делать вывод о сложности решаемых задач по сложности примеров, в которых описываются приемы для их решения.

    Reply
  10. json

    (6) Yashazz,

    Не умеете работать с настройками СКД — нечего позориться.

    Предлагаю Вам три типовые задачки на СКД, которые решаются средствами, описанными в данной публикации.

    Прикладываю скрин. Текущий вид отчета слева. Требуемый вид отчета — справа.

    Прикладываю прототип отчета с результатом как на скрине слева.

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

    Сколько из трех случаев Вы сможете реализовать стандартными средствами СКД?

    Reply
  11. kser87

    (11) смешные примеры) случаи 1 и 2. Вы про горизонтальные группировки не знаете что-ли?

    Простой пример (вместо «Выбора» могут быть элементы справочника. Для наглядности так сделал)

    Выбор когда Условие 1 тогда

    «Мебель»

    Когда Условие2 Тогда

    «Продукты»



    n вариантов

    Конец как ГоризонтальнаяГруппировка

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

    Случай 3 видимо не реализуем настройками СКД. Однако, следующее требование пользователя будет таким: выведите итог по виду товара. И куда вы его впихнете, позвольте узнать? От такого расположения группировок потому и отказались. Наиболее близкий вариант это поставить в параметре «Расположение полей группировок» значение «Отдельно и только в итогах».

    Вообще когда вы корячите макеты СКД помните, что вы с вероятностью 99% что-нибудь сломаете. То есть не будут работать расшифровки, группировки и т.д. и т.п.

    В вашем случае 1 недостаток сразу видно. В примере 1 можно вынести подразделение и сотрудника в отдельную группировку. Таблицу сделайте подчиненной сотруднику и в качестве группировки сделайте например Вид расчета. В таком случае, при количестве сотрудников от 1000 ваш отчет просто «умрет» на отрисовке макета. Будет формироваться минут 30, а вэб-морда тупо вылетит.

    Да и вообще все примеры хорошо сработают лишь на небольших объемах данных. Нужно использовать механизмы СКД. Для замены текста точно УО нужно.

    Reply
  12. json

    (12) kser87, из описания неточно понятно, что именно вы имеете ввиду. К посту 11 приложен внешний отчет. Попробуйте реализовать вашу идею в этом отчете и выложить. Чтобы можно было увидеть, что вы смогли получить требуемый результат без костылей. Можно переставлять так, как считаете правильным. Главное получить ожидаемый результат в виде готового табличного документа.

    Также отмечу, что конструкция Выбор Когда ... — не подходит, т.к. мы не знаем заранее состав и количество элементов в справочниках. Об этом написано в условии задачи

    Вообще когда вы корячите макеты СКД помните, что вы с вероятностью 99% что-нибудь сломаете. То есть не будут работать расшифровки, группировки и т.д. и т.п.

    Вероятность вы взяли из головы. Расшифровки в шапке — дело редкое.

    В вашем случае 1 недостаток сразу видно. В примере 1 можно вынести подразделение и сотрудника в отдельную группировку. Таблицу сделайте подчиненной сотруднику и в качестве группировки сделайте например Вид расчета.

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

    Хочу посмотреть на примере, который вы выложите. Пока я увидел ваше предположение, которое не соответствует поведению СКД

    В таком случае, при количестве сотрудников от 1000 ваш отчет просто «умрет» на отрисовке макета. Будет формироваться минут 30, а вэб-морда тупо вылетит.

    Снова ваше предположение. Вы не можете знать при каком количестве сотрудников она вылетит, т.к. вы не провели эксперимент. Почему вы решили, что 30 минут а не 30 часов? Какое значение имеет количество сотрудников [строк отчета], если обработка производится только в шапке отчета? Почему нельзя формировать табличный документ на сервере?

    По поводу вывода в отчет большого количества данных — я спорить не буду. Вопрос в другом: как часто необходимо выводить в отчет большое количество данных? Как часто в этом случае нужно делать сложные группировки? Действительно ли нельзя оптимизировать мою схему при работе с большим количеством данных?

    В моей практике таких отчетов наберется максимум 5%. И какая-то малая доля из них будет со сложными группировками. Поэтому ваш аргумент по поводу больших данных не отменяет применимости методов, описанных в данной статье.

    Также хочу уточнить, т.к. может быть это не понятно из статьи. Данная публикация описывает приемы решения задач, которые нельзя сделать настройками СКД. В посте 11 я выложил такие задачи. Поэтому я ожидаю увидеть работающий пример, который доказывает, что описанные случаи все таки решаются настройками. Но пока я вижу, что Ваши высказывания, а также высказывания уважаемого Yashazz содержат больше предположений и эмоций, чем фактов

    Reply
  13. rus128

    Все хорошо, но огорчает опечатка в исходнике — название процедуры ОбъединтьЯчейкиВТабличномДокументе().

    Или так было задумано? 🙂

    Reply
  14. json

    (14) rus128, спасибо за замечание.

    Поправил в тексте статьи и в прилагаемом примере

    Reply
  15. stol6

    На какой версии платформы это все дело тестировалось?

    Reply
  16. json

    (16) stol6, хороший вопрос.

    Добавил эту информацию в конец статьи.

    Одно замечание: описанные процедуры работают на платформе 8.1 без изменения, но т.к. в ней отсутствует обработчик ПриКомпоновкеРезультата(), а также есть еще пара нюансов, то незначительно изменил сводный пример для этой платформы

    Reply
  17. sudmorsh

    Спасибо за статью.Уверен, что пригодится.

    Reply
  18. Eriksson

    Как раз задумался о том, как бы реализовать на практике через СКД, пригодится! Спасибо!

    Reply
  19. lomanos

    в копилку +1

    Reply
  20. mafia

    Гениально. Однозначно +5

    Reply
  21. 1C82

    Нужно всем!

    Reply
  22. web_profiler

    Помогите плиз. Третий час туплю

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

    Хочу окультурить вывод дат и сверху над датами (как бы в шапке) написать «Даты ожидаемых платежей».

    Че делать — уже всю голову сломал, и группы где угодно создавал (выводит название этой группы над КАЖДОЙ датой) и че только не делал.

    Не получается окультурить отчет, помогите плиз

    http://i.piccy.info/i9/5b3378e75c26f7bdd38e4e2af709e936/1550217474/11481/12­97933/khelp11.png

    http://i.piccy.info/i9/3b1297de8ba10b23160a9e99bdddcef2/1550217609/34019/12­97933/khelp12.png

    Reply

Leave a Comment

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