Трюки и уловки при работе с отчетами на базе СКД (часть 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='\

59 Comments

  1. mbreaker

    (1) MarSeN, к сожалению не могу подтвердить верность утверждения. При попытке воспроизвести у меня всего лишь схлопываются сами группировки, оставляя при этом заголовок и образуя некрасивую толстую линию на стыке. Смысл трюка №3 был как раз-таки в обратном: оставить выводимые группировки в области данных, но скрыть заголовок группировки в области шапки отчета.

    Reply ↓
  2. MarSeN

    «Шапка-невидимка» — примерно то-же самое можно сделать если в условном оформлении этого поля указать максимальную высоту = 1

    Reply ↓
  3. stanru1

    Спасибо, очень интересно! Хочу больше разных трюков с СКД!

    Reply ↓
  4. hulio

    Век живи — век учись, как говорится.

    Про вариативную расшифровку понравлось решение. Мне самому не приходило в голову )))

    Возьму на вооружение 😉

    Reply ↓
  5. mbreaker

    (5) zqzq, да, на текущий момент это единственный вариант для хоть какого-то оформления дублирующихся ресурсов и реквизитов, т.к. иного механизма пока что не найдено, но при таком оформлении действительно остаётся пустая ячейка в шапке.

    Reply ↓
  6. zqzq

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

    Reply ↓
  7. Поручик

    Статья полезная. Даже сам узнал кое-что очевидное, но для меня было открытием. Выводы: век живи, век учись.

    Reply ↓
  8. kuzyara

    А я тут недавно узнал что и динамические списки на СКД работают 🙂

    И лучшее средство отладки — консоль компоновки данных (ИР от tormozit) с волшебной кнопкой «Открыть запросы макета компоновки в консоли запросов»

    Reply ↓
  9. kuzyara

    (9), Динамический список, это раз.

    Консоль запросов != Консоль компоновки, это два.

    У меня тоже проблемы с чтением бывают;)

    А если попытаться сделать пару отчетов не мышкой, а описать скд с помощью только кода (гилев в помощь), то можно понять объектную модель этой системы, и описанные в статье вещи не будут необычными.

    Reply ↓
  10. mbreaker

    (8) kuzyara, не совсем понял, что подразумевается под динамическими списками в СКД, но недавно в партнерской конференции коллеге объяснял, как под УФ настроить сложносоставной отбор по реквизиту одного из полей.

    А вот с отладкой СКД через консоль запросов я бы посоветовал действовать осторожно. Нисколько не умаляю удобство ИР, но часто бывает, что результаты СКД и запроса сильно разняться. Некоторым особенностям работы СКД планирую посвятить одну из публикаций.

    Reply ↓
  11. mbreaker

    (10) kuzyara, коллега, с чтением у меня пока всё нормально, так что дело не в этом…

    1) Что такое динамический список в УФ я прекрасно знаю, меня смутила фраза «динамические списки на СКД работают», поэтому предположил, что речь идёт об управлении отборами в диалогах выбора, написанных на УФ, т.к. иного варианта, почему работа динамических списков в СКД должна удивлять у меня не нашлось. А вот на тему применения сложных отборов у меня было обсуждение одного из таких случаев с коллегой из Астрахани (ветка «СКД связь полей в отборе по владельцу через промежуточный реквизит» в форуме «Платформа 8.3» партнерской конференции).

    2) Замечательный инструментарий Сергея Седых я знаю давно и также давно им активно пользуюсь в своей работе. Поэтому отличить консоль запросов от консоли компоновки данных у меня сложности не составляет. А моя ремарка про соблюдение осторожности относится к упомянутой кнопке «Открыть запросы макета компоновки в консоли запросов». Дело в том, что в последних версиях конфигураций активно используются функциональные опции, а они очень сильно влияют на результат отработки СКД. Но тот же самый запрос набора данных, открытый через «волшебную кнопку» в консоли запросов полностью их (ФО) проигнорирует и выдаст иной результат.

    Reply ↓
  12. Puk2

    Трюк №2 можно иногда частично заменять определенным образом построенным запросом, но при этом использовать фишку СКД «Игнорировать NULL». Если в группировке попадается поле со значением NULL, но при этом установлено свойство «Игнорировать NULL», то данная группировка просто не выводится, таким образом получаем «умную» расшифровку по уровню. Плюс по сравнению с трюком №2 заключается в том, что записи будут в естественном порядке, а не так, как «вручную» установлены в группировке с отбором. Хотел бы уточнить, что оба метода жизнеспособны и сам их оба активно применяю.

    Так же в качестве трюка СКД можно отметить «левое соединение», которое в плане подсчета итогов не такое «левое», как в запросе. Хотя это правильнее назвать особенностью, а не трюком.

    Reply ↓
  13. mbreaker

    (12) Puk2, да, тоже интересный вариант… но с отбором получается чуть более гибче за счет того, что отборами можно регулировать в вариантах отчета, а с «Игнорировать NULL» только на стадии разработки СКД… ну и, честно сказать, я немного недолюбливаю это свойство, т.к. с составными типами пару раз «выстреливало» не так, как рассчитывал (может в версии платформы проблема была, а может особенности СУБД)… но за идею спасибо!

    Reply ↓
  14. Alex1Cnic

    Молодца!!!

    Очень интересно и ждем продолжений! респкт!

    Reply ↓
  15. gull22

    Полностью присоединяюсь к комментарию (7) Поручик. Буду ждать продолжения.

    Reply ↓
  16. valvit

    Спасибо, познавательно и согласен без снобизма!

    Reply ↓
  17. mikhailovaew

    Отличная статья, полезно, понятно и без снобизма. Пожалуйста, продолжайте!

    Reply ↓
  18. SITR-utyos

    СКД — эх, сколько про неё можно писать… для новичков это очень полезный материал.

    Сам в свое время хотел запутить цикл статей по СКД, но нынешняя система мотивации на инфостарт отбила все желание

    В результате меня хватило только на http://infostart.ru/public/267055/

    Reply ↓
  19. mbreaker

    (18) SITR-utyos, хорошая статья, раскрывающая многие недавно вышедшие в платформе новинки…

    а что не так с системой мотивации инфостарта? сколько помню тут всегда был немонетизированный рейтинг…

    Reply ↓
  20. mbreaker

    (18) SITR-utyos, хотя припоминаю начисление $m за рейтинговые статьи (>100 звёзд) в момент введения $m… как сейчас дела обстоят — даже не знаю…

    Я не отношусь к числу тех, кто стремится заработать на этой площадке… Она мне неинтересна с этой точки зрения, а к рейтингу я лично отношусь, как к оценке признания сообщества моих стараний, а не как ко всем-известно-чего-измерительному инструменту. Хотя даже во втором не вижу ничего противоестественного — человеку свойственны поведенческие «лидерские» сценарии.

    Reply ↓
  21. mulla1979

    Статья отличная! Автору респект!

    Reply ↓
  22. a1ex4ndr

    Отличная статья, плюсанул. Особенно с шапкой-невидимкой пригодилось))))

    Reply ↓
  23. Alex123456

    Хорошая статья. Спасибо.

    Reply ↓
  24. zqzq

    (18) (19)

    Кстати, пользуюсь иногда выводом таблицы в одну ячейку (ВычислитьВыражениеСГруппировкойТаблицаЗначений и т.д.). И что обнаружил — в тонком клиенте 8.2.19.68 при попытке расшивровки/открытия система принудительно валится с ошибкой т.к. недоступна ТаблицаЗначений на клиенте. Приходится изащряться — заключать выражение в СоединитьСтроки(), создавать макет для поля и прописывать расшифровку как Массив().

    С массивом нет проблем с расшифровкой, но вывод в одну строку не очень красив.

    Ещё момент — ВычислитьВыражениеСГруппировкойТаблицаЗначений(«А, Б, С», «А«) и ВычислитьВыражениеСГруппировкойТаблицаЗначений(«С», «А«) по опыту дают одинаковый порядок поля «С», но по справке это не очевидно. Альтернативное выражение очень громоздкое:

    ПолучитьЧасть(
    Упорядочить(
    ВычислитьВыражениеСГруппировкойТаблицаЗначений(
    «С, А»,
    «А»
    ),
    «А»
    ),
    «С»
    )

    Показать

    Reply ↓
  25. tormozit

    (11) Немного поправлю, я Сергей Старых, а не Седых, хотя согласен близко =)

    По поводу функциональных опций кажется, что правильнее всего отлаживать СКД/запрос под нужным пользователем, временно предоставив ему роль ирРазработчик. Для этого в инструменте «Редактор пользователей» есть возможность запустить предприятие под любым пользователем и временно включить ему эту роль.

    Reply ↓
  26. Poplar

    Хорошая статья. Прекрасное оформление. В продолжении, если можно, поясните, как «Первые», используемые в конструкторе запроса задать в виде параметра в настройках отчета? Если, конечно это возможно. Если нет, то как иначе выводить первые, чтобы установка их количества была доступна пользователю?

    Reply ↓
  27. mbreaker

    (25) Сергей, извини за ошибку с фамилией, на самом деле тот пост писал с мобильного и возможно просто случайно ткнул в автоподстановку. Относительно ФО — не важно, под каким пользователем работаешь, ФО влияет на всех, просто в конструкторе СКД таблицы, привязанные к ФО доступны для выбора, но уже на стадии настройки связей начинают сказываться значения ФО. Выполнение такой схемы приводит к ошибке, если ФО отключены, а выполнение запроса из схемы пройдёт без проблем.

    Reply ↓
  28. mbreaker

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

    Reply ↓
  29. tormozit

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

    Reply ↓
  30. Poplar

    (28) Я так пытался в свое время делать но у меня не получилось. Система отказывалась понимать отбор по системному полю. Выкрутился тем, что заказчикам передал три отчета, каждый из которых на разное число строк (топ продаж 10,20,30 позиций номенклатуры).

    Reply ↓
  31. mbreaker

    (29) tormozit, точнее в ближайшую неделю сказать не смогу по причине отпуска. Легко можешь проверить это поведение, сделав в штатной БП 2.0/3.0 запрос к р/с, участвующих в ЭДО.

    Reply ↓
  32. mbreaker

    (29) tormozit, точнее в ближайшую неделю сказать не смогу по причине отпуска. Легко можешь проверить это поведение, сделав в штатной БП 2.0/3.0 запрос к р/с, участвующих в ЭДО. Если ФО «Использовать ЭДО» выключена — схема при выполнении будет выдавать ошибку «Не могу найти поле …»

    Reply ↓
  33. mbreaker

    (26) Poplar, пока нашёл только один способ ограничения вывода количества строк. При выборе конкретной группировки («<Детальные записи>» тоже группировка) на закладке «Другие настройки» появляется настройка «Количество записей». В форме отчёта ОФ можно вывести эту настройку программно, в УФ можно определить её, как «пользовательскую настройку», назвать по своему и управлять ею через «Все настройки…»

    P.S. К сожалению добиться её вывода в настройках быстрого доступа через штатные средства БСП у меня не получилось.

    Reply ↓
  34. Poplar

    Спасибо большое, все работает. Без быстрого доступа обойдусь.

    Reply ↓
  35. mbreaker

    (34) Poplar, рад был помочь.

    Reply ↓
  36. FractonKireyev

    Давно работаю с СКД, и вроде-бы уже всё знаю. А вот трюк №2 (с отбором на группировках) для меня оказался полной неожиданностью.

    Беру на вооружение.

    Reply ↓
  37. Amelk

    (12) Puk2, Спасибо. Очень полезний и не типичний способ

    Reply ↓
  38. DexterMorgan777

    Спасибо.

    Reply ↓
  39. LexSeIch

    Мир этому дому! Статья отличная и полезная. Радует так же аккуратность оформления иллюстраций. Автору спасибо — ждем продолжения!

    Reply ↓
  40. nata_87

    Подскажите пожалуйста как в СКД рассчитать итог по Среднему игнорирую пустые значения, т.е. в отчете 10 строк из них только 3 заполнены, как итоговое среднее вывести по этим трем, так как сейчас он при расчете среднего делит на кол-во строк 10

    Reply ↓
  41. SITR-utyos

    (40) В ресурсе пишешь выражение:

    Сумма(ТвоеПоле) / Сумма (Выбор КОГДА ЗначениеЗаполнено(ТвоеПоле) Тогда 1 Иначе 0 Конец)

    Reply ↓
  42. nata_87

    (41) SITR-utyos, Спасибо!

    Reply ↓
  43. OrsoBear

    Вот спасибо!

    Маялся с группировками, шапки рисовал, а оказалось все гораздо проще решается.

    Reply ↓
  44. Aprobator

    хм, а вот такая проблема. Как в схеме СКД обойти проблему с выводом при расшифровке строк с пустым значением ресурса?

    Исходные данные:

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

    Reply ↓
  45. mbreaker

    (44) Aprobator, не совсем понятна задача. Что означает «при расшифровке»? Разворот группировки или drill-down отчет? Или что-то иное?

    Можно чуть более развернуто и желательно с визуализацией?

    Reply ↓
  46. alina71

    Не подскажете как решить такую задачу: если взять пример из трюка 1, то чтобы в отчет выводились только контрагенты, у которых «Обороты за период» были больше определенной суммы, ну например 100 тыс? То есть ИЛИ дебет ИЛИ кредит были больше этой суммы? Как я понимаю, если через отбор поставить два условия, они выполняются через «И», т.е. выберутся контрагенты, у которых и дебет и кредит больше 100 тыс.

    Reply ↓
  47. alina71

    вернее, отбор вообще не выполнится, отчет будет пустой

    Reply ↓
  48. mbreaker

    (46) очень просто: добавить в отбор группу типа «ИЛИ». Через кнопку «Добавить», подменю «группу» или выделить условия, нажать правую кнопку мыши и выбрать «Сгруппировать». Группы между собой также можно группировать, формируя сложные комбинации условий отбора.

    Reply ↓
  49. alina71

    Констатин, спасибо большое, сама что-то не догадалась. Все получилось, единственное почему-то пропало сальдо на начало периода((

    Reply ↓
  50. alina71

    Вопрос решен. Поставила отбор не на уровне всего отчета, а на группировке «Контрагенты».

    Reply ↓
  51. KAV2

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

    1) задать в условном оформлении группировки высоту 0.5 (меньше не работает) и задать область действия — заголовок (Field header).

    2) (не обязательно но выглядит лучше) в условном оформлении группировки указать отсутствие рамки со всех сторон и задать область действия — заголовок (Field header).

    3) (не обязательно но выглядит лучше) у ближайших по иерархии вложенных группировок, в условном оформлении указать отсутствие рамки со всех сторон и задать область действия — заголовок (Field header).

    Проверялось на УФ, на платформе версии 8.3.8.2322

    Reply ↓
  52. XelOla

    (12) подскажите пожалуйста

    как «свернуть» строки

    Reply ↓
  53. корум

    (53)

    как «свернуть» строки

    не использовать «количество», не?

    Reply ↓
  54. XelOla

    (54)

    не поняла

    Reply ↓
  55. корум

    (55) подробно напишите, что есть «свернуть» строки.

    Что нужно добиться?

    Reply ↓
  56. XelOla

    (56)

    Reply ↓
  57. корум

    (57) разобраться с документами, т.к. приход без указания склада, а расход со склада ромашка.

    Reply ↓
  58. XelOla

    (58)

    нет.

    в базе отключен учет МПЗ по складам. Но в документах он присутсвует, его указывают.

    Пустое место — это Ввод начальных остатков. там в каждой строке должен указываться склад прихода

    Но у нас отключен учет по складам (

    можно ли просто — свернуть?

    Reply ↓
  59. корум

    (59) убери группировку склад.

    и да, для таких вопросов лучше заводить новую тему.

    Reply ↓

Leave a Comment

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