Работа с MS Word из 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='\

57 Comments

  1. maXon777

    Прекрасный обзор! Спасибо!

    Очень понравился подход с программным заполнением таблицы путем добавления строк!

    Reply
  2. GOOD256

    Огромное спасибо!!!

    Reply
  3. pvl_mksv

    Коротко и по-теме! +

    Reply
  4. gradi

    В ворд2013 глюков с DOCVARIABLE не замечал.

    Reply
  5. DJDUH

    Самая «засада» MSWord — это вставить значение в шейпы или иные надписи и картинки — сколько не игрался так и не получилось, найти выход — находит нужное, а значение вставить фига(

    Reply
  6. director04

    Поставил плюс за краткость. И хотел бы еще одни плюс за заголовок.

    Хотя,… есть тут пара засранцев, которые обязательно нагадят, что де «все это всем давно известно…»

    Спасибо, плюс

    Reply
  7. Сурикат

    (4) gradi,

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

    Reply
  8. Сурикат

    (5) DJDUH,

    К сожалению или к счастью с таким не сталкивался =)

    Могу только посоветовать покурить MSDN в части свойств и методов указанных вами коллекций. Если получиться, дайте знать. Добавлю к публикации =) Ну или сами созреете для написания кратенького гайда =)

    Reply
  9. gradi

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

    Reply
  10. nni93

    Полезно, спасибо =)

    Reply
  11. AndMax

    Коротко и красиво, спасибо, +

    Reply
  12. stilet

    Подскажите, может кто нибудь сталкивался — как изменить цвет фона у какого нибудь набора символов (скажем двух или трех слов)

    Reply
  13. Сурикат

    (12) stilet, а он у вас все время разный?

    Reply
  14. v3rter

    Базовый метод работы с Word — записываем макрос с нужными действиями, читаем его, читаем хелп к нужным командам, чистим макрос от лишних действий и параметров, копируем в 1С, добавляя «ДокументВорд.» перед командами.

    По поводу параметров — был и есть старый дедовский метод, когда параметр вставлялся в виде текста типа [Мой_параметр], {Мой_параметр}, [{(%%Мой_параметр%%)}] — на выбор, затем командной поиска и замены самого ворда параметры меняются на значения.

    Кстати, проверяли: Application.Visible = False вначале и Application.Visible = True в конце действий ускоряет или нет?

    Reply
  15. v3rter

    (12) stilet, если выделенного текста желтым, то

    Selection.Range.HighlightColorIndex = wdYellow
    Reply
  16. sudmorsh

    Очень полезно, спасибо 😉

    Reply
  17. v3rter

    Записал в ворде макрос замены текста во всем документе, кроме колонтитулов.

    Selection.Find.ClearFormatting

    Selection.Find.Replacement.ClearFormatting

    With Selection.Find

    .Text = «что»

    .Replacement.Text = «на что»

    .Forward = True

    .Wrap = wdFindContinue

    .Format = False

    .MatchCase = False

    .MatchWholeWord = False

    .MatchWildcards = False

    .MatchSoundsLike = False

    .MatchAllWordForms = False

    End With

    Selection.Find.Execute Replace:=wdReplaceAll

    Selection.EscapeKey

    Показать

    Возможно, будет полезен.

    Из хелпа:

    WdReplace

    Constant Value

    wdReplaceAll 2

    wdReplaceNone 0

    wdReplaceOne 1
    Reply
  18. monkbest

    (17) v3rter, зачем искать в цикле?

    я делаю так

    ТекДок.Content.Find.Execute(«%параметр%,,,,,,,,,»мой текст»,2);

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

    Reply
  19. v3rter

    (18) monkbest, ну так я на это и намекал. Ждём от автора версию 2.0

    Reply
  20. Сурикат

    (14) v3rter,

    Application.Visible = False вначале и Application.Visible = True в конце действий не ускоряет процесс. Проверил =)

    Reply
  21. isanka

    Спасибо за труды.

    Для старта очень познавательно.

    Вопрос.

    как прочитать текст содержащийся в полученной таблице ?

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

    (пробовала заполнять в цикле (Таблица.Cell(ИндексСтрока+1,ИндексСтолбец+1).Range().InsertAfter(Текст),

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

    или это из области фантастики?)

    Reply
  22. Сурикат

    Приношу извинения за небольшие проблемы с форматированием =(( Подвел новый редактор.

    Reply
  23. Сурикат

    (21) isanka,

    Мне другие способы не знакомы. Можно заполнять же только некоторые ячейки. Обращение по номеру строки/столбца это позволяет.

    Поищите как word с ADO дружит =) В Excel ADO дает неплохой прирост производительности. Если найдете, дайте знать =) Добавим в публикацию =))

    Reply
  24. v3rter

    (21) isanka, Попробуйте Таблица.Cell(ИндексСтрока+1,ИндексСтолбец+1).Range().Text или Таблица.Cell(ИндексСтрока+1,ИндексСтолбец+1).Range.Text

    Всё это гуглится, но не на русском: https://msdn.microsoft.com/ru-ru/library/office/ff821612.aspx

    Reply
  25. freud

    windows 10 + ms office

    1c выдает

    ОбъектВорд = Новый COMОбъект(«Word.Application»)

    Не удалось создать объект.

    Возможно, отсутствует соответствующее приложение.

    в чем причина

    Reply
  26. sssss_aaaaa_2011

    (25) В том, что последние версии оффиса не имеют СОМ-объектов.

    Reply
  27. Сурикат

    (25)А где выполняется код? на сервере или на клиенте?

    Reply
  28. HalfZer0

    Я требую больше версий слова Стурктура, то есть Струкутра, то есть… ааааа!!!

    Reply
  29. fish249

    Полезная статейка

    Reply
  30. MiniGrad2014

    Не помещая документ в макет можно напрямую заполнять поля шаблона ворда?

    Reply
  31. Tanis

    Доброе утро!

    Как раз очень нужный вопрос.

    Подскажите, плиз. Выполнение заполнения шаблона происходит на стороне клиента (пользователя) или на сервере?

    Если есть вариант заполнять именно на сервере, то как это можно реализовать?

    Спасибо!

    Reply
  32. Сурикат

    На сервере можно заполнять только в том случае, если стоит на нем Word. Иначе только ковыряние в XML.

    Reply
  33. Tanis

    Да. Поставили туда специально Ворд.

    А как осуществить это? подскажите, пожалуйста.

    Как передать макет на сервер, до его получения пользователем?

    Спасибо!

    Reply
  34. tjurikov_ivan

    (33) В 1С ДО заполнение шаблонов на сервере происходит через фоновое задание

    Reply
  35. user697645_gonchar.m

    Спасибо!

    Reply
  36. Сурикат

    Эм…

    У вас 1с ДО?

    Можно и без фонового задания.

    Сохраняете в двоичные данные, а на сервере получаете.

    Если нужно пользовательский макет, то двоичные данные сериализуются

    Reply
  37. Tanis

    Хм….

    Тогда еще вопрос, а как сохранить этот шаблон в двоичные данные, для передачи на сервер?

    Макет сделан как Актив документ.

    Word = ЭтотОбъект.ПолучитьМакет(«ШаблонВорда»).Получить();

    При этом сразу ошибка, что мол нет программы….

    Reply
  38. Сурикат

    А зачем вам макет active document, если можно сразу сделать двоичные данные и передавать на сервер?

    Ведь вы все равно его для заполнения будете на диск сохранять =)

    Reply
  39. Tanis

    Так макет же является — актив документ.

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

    Reply
  40. Сурикат

    (39)

    Не используйте актив документ =) Это достаточно ущербная вещь, использование которой не дает никаких преимуществ, а добавляет только проблем.

    Reply
  41. Tanis

    Добрый вечер!

    А чем они стали ущербные ((((

    Что предлагаете? Держать шаблон на диске или вообще перетаскивать в макет?

    Спасибо!

    Reply
  42. Сурикат

    Ущербные потому что править их довольно-таки тяжело, неудобный интерфейс. Возможно я что-то не знаю или это субъективно…

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

    Reply
  43. artms

    А почему не напечатать на сервере? https://infostart.ru/public/675307/

    Reply
  44. bondar_vy

    Коллеги, добрый день. Столкнулся с тем что в ЗУП 3.1 платформа 8.3.10.2667 при загрузке шаблона word 2013 не подтягиваются колонтитулы и рисунки. Может нужны какие-то специальные настройки в 1С или в word? Подскажите пожалуйста.

    Reply
  45. Pavel Rodinchenko

    Спасибо за статью. Очень полезно

    Reply
  46. AlexeyK1

    А что же самых маленьких не учим с пеленок за собой убирать?

    надо бы добавить уничтожение объектов и файлов.

    а так статья хорошая )))

    РS а то как открывать учим

    //Разумеется, получение COM-объекта нужно поместить в попытку. Мало ли, что-то пойдет не так.

    а как в Исключении прибить и почистить нет

    Reply
  47. Сурикат

    (46)

    Я как-то верю в умные указатели…

    Думаете не стоит? =)

    Спасибо за замечание =)

    Reply
  48. Forrest_Gump

    Подскажите а чем могут быть «тормоза»???…

    простенький шаблон договора 6 страниц… 30 параметров для замены…

    Reply
  49. pchelov

    Метод «Execute» имеет ограничение на длину значения для замены в 255 символов, если будет больше, то появляется исключение. Я написал небольшую процедуру для выполнения замены частями:

    Процедура ВыполнитьЗаменуСОграничениемДлиныСтроки(вхДокументВорд, вхШаблонЗамены, вхЗначение)

    // Замена значений в ворде имеет ограничение на длину в 255 символов.

    // Разобьем значение на куски по 255 знаков

    МаксДлинаСтроки = 255;

    ИДШаблона = «@»+СтрЗаменить(Новый УникальныйИдентификатор, «-«, «»);

    МаксДлинаСтроки = МаксДлинаСтроки-СтрДлина(ИДШаблона);

    ТекШаблон = Строка(вхШаблонЗамены);

    НеРазбитоеЗначение = Строка(вхЗначение);

    МассивЧастейСтроки = Новый Массив;

    Пока СтрДлина(НеРазбитоеЗначение)>0 Цикл

    ЧастьНужнойДлины = Лев(НеРазбитоеЗначение, МаксДлинаСтроки);

    МассивЧастейСтроки.Добавить(ЧастьНужнойДлины);

    НеРазбитоеЗначение = Сред(НеРазбитоеЗначение, МаксДлинаСтроки+1, МаксДлинаСтроки);

    КонецЦикла;

    Для Каждого ЧастьСтроки Из МассивЧастейСтроки Цикл

    вхДокументВорд.Application.Selection.Find.Execute(ТекШаблон,,,,,,,,, ЧастьСтроки+ИДШаблона, 1);

    ТекШаблон = ИДШаблона;

    КонецЦикла;

    вхДокументВорд.Application.Selection.Find.Execute(ТекШаблон,,,,,,,,, «», 1); // Зачистим остатки шаблона

    КонецПроцедуры

    Reply
  50. user608357_elpst

    Добрый день. А не подскажите — можно ли в созданный документ *.docx в нижний колонтитул внести произвольный текст и номер страницы?

    Reply
  51. named_Alexander

    А куда писать этот код ? Мне надо его в Справочник, модуль формы элемента поместить, чтоб Договор заполнялся данными из формы элемента. Создал в нужном мне справочнике макет с двоичными данными, потом в форме элемента создал кнопку и в событиях кнопки вставил код, Но он не работает там. Еще непонятно, где что выполняется, что на клиенте, а что на сервере ? Подскажите пожалуйста 1С УТ 11

    Reply
  52. Сурикат

    (51)

    В УТ11 сложнее. На сервере или на клиенте у вас Word стоит?

    Reply
  53. named_Alexander

    (52)

    На клиенте.

    Reply
  54. user1132956

    Очень не понятно! решил впервые распечатать из Word, и что в итоге? Добавил файл ворд в макеты через двоичные данные, вставил код, сразу же заругался на «ДополнительныеПараметры.ВидДоговора» — что это такое, откуда брать и зачем? если уж называете статью, для самых меленьких, тогда хоть что-то объясняйте

    Reply
  55. Сурикат

    (54)

    К сожалению, в одной статье не научить программированию и одновременно работе с word =(

    Если бы вы открыли в синтакспомощнике описание метода ПолучитьМакет, то увидели бы, что он принимает в качестве первого параметра имя макета с двочиными данными =)

    Reply
  56. rjkjlptq

    Добрый день!

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

    Для каждого Параметр Из СтруктураПараметров.ТЧПостояннаяЧасть Цикл

    СтруктураПараметров.ДанныеШапка.Площадь = Формат(Параметр.Площадь,»ЧЦ=15; ЧДЦ=1″);

    КонецЦикла;

    Reply
  57. Сурикат

    (56)

    как вывести все значения через запятую в строку без использования таблицы.

    Несовсем понятно какие данные на входе и какие должны быть на выходе…

    P.S.

    Возможно вам поможет СтрСоединить()

    Reply

Leave a Comment

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