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

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 не будет опубликован. Обязательные поля помечены *