Один способ вносить изменения в типовую конфигурацию без проблем с обновлением




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

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

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

<?php // Полная загрузка сервисных книжек, создан 2025-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='\

36 Comments

  1. Aleksey_3

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

    А по поводу регионов … к примеру в БП 2.0 появился механизм дополнительных реквизитов, который прекрасно вписывается в типовые отчеты и позволяет пользователю отбирать по этим реквизитам

    Reply
  2. iov

    Встречал решение с использованием «свойств документов» соответственно отчеты строились дольше но при обновлениях проблем не было…

    Но как говорится каждое решение имеет место быть..

    Reply
  3. wirg

    как обычно, автор не учел категорий и свойств, на крайняк можно из регистратора всё взять и ничего особенно не менять.

    Reply
  4. zfilin

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

    Вы, конечно, правы про категории и свойства и про проведение документа. Но, как сказал уважемый iov, решений может множество. Все зависит от конкретной ситуации.

    Reply
  5. DoctorRoza

    Согласен с Aleksey_3 по поводу работы с транзакциями и блокировками. Это основные, подводные камени, которые следует учитывать при работе в клиент-серверном режиме. Предложенное автором увеличивает объем базы, но решает проблему обновления, в первом приближении. Наибольший интерес вызывает применение данного метода к 8.2! Тут уже придется учесть еще и применение директив компиляции у процедур и функций!

    P.s. Идея, в принципе не нова, но за понятное, общее объяснение принципа плюсану! ))

    Reply
  6. SergeyT2006

    Для 8.0 не подходит, ибо нет там механизма подписки

    Reply
  7. Craig

    ХМ… возможно вы меня раскритикуете, но не проще было бы создать Справочник.Регион. с реквизитами типа «Регион» и «Ссылка на документ». И добавить во вкладку ввод на основании. Где сразу же создается новая форма, пользователь может спокойной внести необходимые сведенья, нажмет сохранить и вот оно щастье. И выдернуть будет легко для отчета, сильно система не будет нагружена и самое главное обновить не составит особого труда… Ах да с транзакцией проблем не будет, да и по времени программирование по моему способу займет гораздо меньше.

    Reply
  8. zfilin

    DoctorRoza: Спасибо!

    SergeyT2006: Спасибо, подредактирую тэги.

    Craig: Я уже заметил что пример слишком простой. Может быть нужно было описывать две дополнительные аналитики одновременно или ввести дополнительные ограничения, которые бываю (например, когда документ-обертка должен делать ЕЩЕ и свои движения). Но зато такое мое упрощение примера натолкнуло меня на новые мысли благодаря вашим комментариям.

    Reply
  9. KRIHA

    а еще полезно общие модули копировать :), из которых вызываются процедуры и функции документа «обертки» ), а то как обновиццо конфига — общие модули перемелятся в труху, функции и процедуры поменяют место жительства и «ФИО» и все — играла волына и доигралась 🙂 — не будет работать документ «обертка», а ты к тому времени (по заявкам телезрителей) — накрутил много много фенечек и терять все это жалко.

    Reply
  10. o.nikolaev

    Вообще, если бы в 8-ку добавили понятие «Модуль» такое же как понятие «Форма», то все было бы гораздо проще. Имеем: Форма — ОсновнойМодульФормы, дополнительные модули формы, Документ — ОсновнойМодульДокумента, дополнительные модули документа, тогда все изменения сводились бы к тому что основные модули отцеплялись и основными делались бы добавляемые модули. Т.е. грубо говоря нужно в платформу добавить понятие «МодульОбъекта» и иметь возможность работать с ним так же как сейчас с формами. Надеюсь понятно объяснил 🙂

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

    Reply
  11. tango

    чёта туплю я. зачем обновляться, если потом «перецеплять обратно основные объекты»?

    Reply
  12. zfilin

    Обновляться потому, что основной разработчик тоже модернизирует конфигурацию и вносит полезные правки. Вот и получается, что нужно обновить все что в конфе «родное», но при этом не поломать «свое».

    Reply
  13. alexk-is

    (0) Можно не создавать дополнительный документ, а добавить только реквизит и форму в существующий документ. Проблем с обновлением быть не должно, если знаешь как обновлять.

    Текст модуля в публикации можно раскрасить получше. 🙂

    Reply
  14. zfilin

    Спасибо, отлично раскрашивает. =)

    И статья об обновлении хорошая.

    Reply
  15. sss999

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

    Reply
  16. ups9999

    Гы. Добавляем реквизиты объекту. Переопределяем «ПередОткрытием» динамически добавляем реквизиты на форму. Подписка обеспечит нужное проведение. Все имения кода это 3 добавленные в модуль строчки. Их полагаю любой может перенести при обновлении 😉

    Reply
  17. tango

    (12) ок. «полезные» изменения 1с — там, где «перецепляем» или где-то в другом объекте?

    Если там же, то по-любасику надо адекватно изменять свое. Если в стороне — то и обновляем только это. Что пропустил?

    Reply
  18. mus2008

    Жуть. Может пример неудачный приведен? Дублировать документы из за реквизита? Если уж на то пошло, проще создать регистр сведений и посредством его увязать контрагентов и регионы. Это самый простой вариант. Второй, чуть более сложный — свойства сделать у контрагента. В бухгалтерии этого нет, но привязывается легко. В крупных конфах это уже есть. Но тогда:

    База не пухнет необоснованно (я считаю, что в данном случае это именно так).

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

    И восстановление последовательности, особенно накрученное, когда .Восстановить() не прокатывает. Там вообще че-то малопредставимое будет…

    Reply
  19. FormatC

    Замечу, что иногда в типовых конфигурациях некоторые отчеты работают с привязкой к конкретному виду документа. Например, в КА отчеты по заказам и резервированию. И данный способ не прокатит.

    Reply
  20. zfilin

    FormatC: Да, ну, так ведь фишка именно в том, что движения делает именно родной документ.

    А отчеты, которые будут учитывать и дополнительную аналитику все-равно писать самому.

    Reply
  21. zfilin

    tango: Ну, да. Об этом и статья.

    Reply
  22. PopAndr

    Статья затрагивает очень актуальную тему, но вариант решения, по-моему, слишком затратный — создавать специальную сущность (ссылочный объект) только ради того, чтобы заполнить дополнительный реквизит регистра накладно не столько с точки зрения размера базы, сколько из-за разрушения логической структуры информационной системы. Представляете, во что превратится конфигурация при использовании данного подхода при значительных изменениях в регистрах и функционале. Тем более что в приведенном примере достаточно иметь:

    1. Регистр сведений, который позволяет хранить значение нужного реквизита документа.

    2. Новая форма стандартного документа, в которую добавлено поле редактирования записи регистра сведений. При этом нет необходимости делать его с привязкой к регистратору, достаточно сделать измерение регистра по документу ведущим.

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

    Reply
  23. Арчибальд

    Решение спорно. Но изложено внятно, а предмет статьи актуален. Ergo, плюс.

    Reply
  24. RailMen

    Комменты не менее ценные чем самастатья 😉

    Reply
  25. I_G_O_R

    регистры, дополнительные формы, дополнительные документы….

    а про пользователя и не подумали: будет ли ему удобно так работать?

    Reply
  26. zfilin

    I_G_O_R: Подумал — неудобно. О чем и писал. А на самом деле все зависит от реализации, порой пользователю оказываются удобны самые неожиданные вещи. =)

    Reply
  27. flagman

    статья писалась не для внесения одного реквизита. Сам делал практически тоже самое: нужен был аналог «поступления товаров» и «расходной накладной» НО со своими табличными частями, кучей доп. реквизитов, + движения по 5 НОВЫМ опер. регистрам.

    отличие от статьи только в том, что на типовой документ, кот. создан автоматически накладывался ПОЛНЫЙ запрет на изменение (контролировалось по тому же самому регистру сведений). Т.е. все изменения только ч/з новый документ.

    Основная беда — потеря скорости проведения документов (за счет необходимости синхронизации). Но расхождений данных нет

    Reply
  28. gusinea

    Согласен с «PopAndr» можно сделать доп. форму в том же документе, назначить её ОСНОВНОЙ, а при обновлении максимум что случится — слетит эта настройка(поправляется в течении неск. секуд). Зато отпадает надобность в синхронизации документов

    Reply
  29. aegoncharov

    Это же так называемая методика «мегадокументов». Позволяет создать прослойку между пользователем и типовым функционалом.

    4 основные проблемы:

    1. Длинные транзакции при записи

    2. Более быстрый рост базы

    3. При обновлении все равно приходится поверять работоспособность мегадокумента. из-за изменений общих модулей, но это не сложно.

    4. Усложняется настройка обмена в распределенных базах.

    С проблемой №1 наверное буду бороться, реализовав «отложенное создание» подчиненных документов.

    Reply
  30. Lancelot-2M

    Для одного дочернего документа реквизита хватит, а вот для цепочки регистр сведений в самый раз — респект и уважуха автору)))

    Reply
  31. zhleonid8

    эту статью нужно в первый день работы програмисту дать

    Reply
  32. zhleonid8

    а то по очереди исправляют, а обновлять потом не возможно:)

    Reply
  33. zfilin

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

    В общем, тут нужен баланс между «не трогать как есть» и «добавить немного», понимание ситуации, ну и включение мозга в целом. А-то дашь новичку такую статью, а он ради одного реквизита целую подсистему наворотит. И хрен разберешься потом.

    Но с тем, что «а то по очереди исправляют, а обновлять потом не возможно» согласен. Достали до невозможности. =)

    Reply
  34. zfilin

    Да, и кстати, это все в конечном итоге упирается в «золото разработки», такое как «изоляция кода», «декларирование интерфейсов» и прочее. Эх, когда уже заживем по-человечески?!… =)

    Reply
  35. zhleonid8

    в результате 2 летней работы в 8 понятно, лучше не изменять код а решать штатными средствами

    Reply
  36. zfilin

    Ага. Самый лучший способ разработки — ничего не разрабатывать.

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

    Reply

Leave a Comment

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