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




Принцип обмена данными из 1С с сайтом (на MySQL) и выдачи (публикации) этих данных по запросу.
PHP-Скрипт автоматической загрузки данных из файла данных в формате CSV в базу данных сайта работающего на WordPress.

В продолжение моей темы: 1С:Альфа-Авто Автосалон Автосервис: обмен с сайтом.
С помощью данного скрипта можно загружать в автоматическом режиме, по расписанию, данные сервисных книжек (ремонтов авто) из 1С:Альфа-Авто Автосалон Автосервис.
Также можно загружать данные в ручном режиме: для этого делается скрытая страница, где размещается специальная кнопка.
Комментарии размещенные внутри скрипта разъяснят логику и порядок действия.
Комментарии с "/////    echo" использовались для отладки.
Дополнительно создана таблица для журналирования результатов загрузки данных.
Скрипт включает в себя защиту от SQL инъекций (думаю безопасность соблюдена в полной мере).
В кратце:
1. Пишется скрипт, который запускает этот.
2. Создается регламентное задание в WordPress, по которому запускается скрипт из п.1. 
3. Этот скрипт осуществляет проверку на существование файла обмена в папке.
4. Если данные не новые, загрузка не производится.
5. Если данные новые, очищается таблица сервисных книжек.
6. Загружаются новые данные.

Собственно сам скрипт:

<?php // Полная загрузка сервисных книжек, создан 2026-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 не будет опубликован. Обязательные поля помечены *