Документооборот 8: Расширяем возможности автозаполнения шаблонов документов в 1С или XML-инъекция




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

39 Comments

  1. Yashazz

    Класс! Отличная идея. Кстати, навело на мысль, что в любые строковые реквизиты неограниченной длины можно пихать свои xml, в т.ч. содержащие многострочные данные, лопатить их сериализатором и иметь хранение «табличных» данных.

    Reply
  2. Aleksandr_K

    (1) Yashazz, или в ХранилищеЗначения, например в регистре хранящем настройки отчетов и обработок в УТ, КА и УПП.

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

    Reply
  3. ivdic

    неплохо бы еще вставлять в документ в нужное место печать и клеше (подпись руководителя)

    Reply
  4. soap

    Хороший подход ! Однозначно+

    Reply
  5. Aleksandr_K

    (3) Без доработки типовой тут уже не обойдется. А почему не хотите сделать это изначально в шаблоне для автозаполнения?

    Reply
  6. karapuzzzz

    У меня, конечно, не без доработок, но вот что реализовано:

    1. Возможность вставлять таблицу в поле (а не заменять текст), что дает возможность перезаполнять документ сколь угодно раз

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

    3. Вставлять картинку. При этом, картинка записывается в базе отдельным файлом.

    4. Вставлять текст одного документа в другой.

    Для реализации 3-4 пункта пришлось пойти на костыль: картинка или содержимое вставляется не непосредственно в поле документа, а рядом. При этом вокруг вставленного объекта создаются дополнительные поля на подобии открывающего и закрывающего тэга. Сделано это из-за ограничения поля, но для возможности перезаполнять документ неоднократно.

    Сейчас я сильно занят, но когда более-менее освобожусь — обязательно напишу статью на эту тему.

    Reply
  7. Atori-kun

    ФактическийВладелецФайла — Это ссылка на владельца файла, а ТарифнаяСетка — ? Это не дополнительный реквизит, значит все равно пришлось в конфигуратор лезть?

    Reply
  8. Atori-kun

    (6) karapuzzzz, Время не появилось свободное?

    Reply
  9. Aleksandr_K

    (7) В конфигуратор лезть в любом случае придется.

    ФактическийВладелецФайла — Ссылка на элемент справочника для которого формируется файл.

    Тарифная сетка — не типовая табличная часть объекта

    Reply
  10. hvitaly

    Спасибо! Это то простое решение, которое я ищу последние полгода 🙂

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

    Еще раз спасибо!

    Reply
  11. SidorovNN

    Добрый день!

    Подскажите пожалуйста. Тег «</w:t></w:r></w:p>» формирует абзац с пустой строкой? Столкнулся со следующей проблемой. Если данные файла обновлять по кнопке «Заполнить файл данными документа», то текст, вставленный через теги, постоянно смещается на одну строку вниз.

    Reply
  12. Aleksandr_K

    (11) SidorovNN, данные теги закрывают текущий параграф, а добавляемые в конце — открывают новый параграф. Если стилями предусмотрен отступ — будет выглядеть как пустая строка.

    Чтобы сказать что-то более детальное — хотелось бы увидеть структуру документа в месте вставки.

    Reply
  13. SidorovNN

    (12) Aleksandr_K, во вложении файл. С помощью тегов заполняю поле «Получатель». При заполнении сначала вставляется пустая строка, потом сам текст. Если данные файла обновлять данными документа, то текст смещается вниз.

    Reply
  14. SidorovNN

    (12) Aleksandr_K, Не удалось выяснить причину?

    Reply
  15. Hateful72

    не актуально с релиза 2.1 где то. Общие модули автоподстановки немного переделали

    Reply
  16. crushos
    Reply
  17. Zanuda1977

    2.1.11.5 к сожалению не работает.

    Reply
  18. podkova

    подскажите как решили вопрос?

    Reply
  19. awe007

    Очень актуальный вопрос. Коллеги, подскажите, есть ли какие то рабочие способы вставки табличной части в шаблон на актуальной версии ДО КОРП 2.1.12.2 ?

    Reply
  20. Оберон

    вставил лист согласования — полет нормальный

    Reply
  21. Оберон
    Reply
  22. Оберон
    Reply
  23. Оберон

    (17) привет, попоробовал переделать под себя — работает. см (21)

    Reply
  24. Оберон

    (19) смотри мой вариант

    Reply
  25. Оберон

    (19) получилось сделать свой вариант, см. (21)

    Reply
  26. awe007

    (21) Спасибо большое за пример! А можете пояснить новичку, если не трудно?

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

    Т.е. вся таблица изначально формируется в 1С и потом целиком как есть вставляется в Word?

    Reply
  27. Оберон

    (26) тут все просто..

    1. Конфигуратор:

    в ДО в новый Общий Модуль (ухОбщийМодульПовтИсп) со следующими свойствами(Сервер, Вызов сервера, Повторное использование возвращаемых значений = На время сеанса ), вставляете указанную функцию, сохраняем.

    2. WORD:

    создаем в шаблоне ворд текстовый параметр, поле, как при других вставках автозаполнения, например «ТаблицаСогласовантов»

    3. Предприятие:

    в скриптах автозаполнения выбираем это поле и для него вставляем скрипт автозамены что я привел.

    4. получаем на выходе таблицу согласовавших данный документ.

    Профит!

    Reply
  28. awe007

    (22) Это просто праздник какой-то! Всё работает! День прожит не зря!

    Спасибо вам от всей души!

    Только ещё один маленький моментик.. таблица вставляется, но без рамок (без границ). Можно ли это победить?

    Reply
  29. Оберон

    (28) у меня сетка отображается — возможно у вас в шаблоне ворда стоит не отображать сетку

    Reply
  30. awe007

    И последний вопрос, если позволите 🙂

    Как вы добыли XML-код заголовка таблицы и строки таблицы?

    Я нарисовал нужную мне табличку в ворде, сохранил, разархивировал, нашёл там document.xml, но как в нём понять что относится к шапке страницы, а что к строке?

    Может есть какие то хитрости, типа онлайн-генератора xml? 🙂 Или только руками и глазами отделять тэги друг от друга?

    Reply
  31. Оберон

    (30) хитростей нет — открыть с помощью браузера — EDge или exploer или Chrome и т.д.

    Table ( Tbl ) таблица

    row ( tr ) строка таблицы

    column ( tc ) колонка таблицы

    <w:tbl> — таблица начало

    <w:tr> — строка начало

    <w:tc> — колонка начало

    Reply
  32. Katty_K

    (31) Добрый день!

    Скажите, а с проблемой перезаполнения таблицы данными Вы не столкнулись?

    Я настроила все по Вашим постам, все прекрасно работает, и радовалась до момента, когда попробовала перезаполнить файл данными документа (а это надо будет делать неоднократно).

    В итоге получается то, что на скрине :(((

    Таблица в таблице и т.д…

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

    Reply
  33. Оберон

    (32) это надо смотреть как вы табличку нарисовали, там какая то ошибка, при перезаполнении данными на корректных таблицах так не должно быть, это ошибка шаблона (тега таблицы)

    в моей доработке такого не встречалось.

    Reply
  34. Katty_K

    (33) Взяла целиком Ваш код скрипта и Вашу функцию.

    При перезаполнении файла получается то же самое…

    Reply
  35. Myxa

    (34) Добрый день!

    Аналогичная ситуация!

    Reply
  36. Hood

    (32)Добрый день.

    Получилось победить?

    Reply
  37. Katty_K

    (36) Здравствуйте. Нет 🙁

    Reply
  38. bpirate999

    Не работает. Только теги ворда в тесковом поле

    . Почему?

    Reply
  39. user682069_tulipadanys

    (38)

    // Добавим переносы строки для записи в xml без обработки

    РезультатОбработки = Символы.ПС + СтрЗаменить(РезультатОбработки, Символы.ПС, «») + Символы.ПС;

    Reply

Leave a Comment

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