7.7 Расширяем функционал работы с Таблицей Значений




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

35 Comments

  1. CheBurator

    порадовал флажок «эрегировать» и менюшка «по возврастанию»..

    кто на кого эрегирует и куда врастает?

    😉

    Reply
  2. Noy

    (1) а, пусть так и будет 🙂

    спасибо за оценку.

    Reply
  3. sergeevn1

    Если на форме несколько таблиц значений, то приходится сначала выбирать таблицу левой кнопкой, чтобы на ней заработала правая

    Reply
  4. Noy

    (3) Да, специально так сделал. ТЗ должна быть активна.

    Reply
  5. andrewalexk

    🙂

    Кулибин..

    РедакторТЗ.ert видел хоть?

    Reply
  6. Noy

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

    К тому же в описании четко написано «Это пример того…»

    З.Ы. не все умею классы добавлять — а это работает без внедрения вообще.

    Reply
  7. vasilykushnir

    > P.S. Если вы используете в своей конфигурации «дополнительные глобальные модули», создаваемые с помощью Formex, то обработка работать не будет.

    А че ж так?… Уже хотел опробовать…. А доп модулей у меня немеряно…

    Reply
  8. Noy

    (7) Или я не до конца разобрался с методами Формекса по работе с глобальным модулем, или там всего-то пара методов — но определить загружен ли «мой» глобальный модуль или нет я не смог. Прикручивать сюда еще одну ВК показалось лишним.

    В принципе можешь закоментировать в ПриОткрытии строку с доступностью и все заработает, только посмотри предопределенные процедуры…

    Reply
  9. Abadonna

    (8) ПриОтжатииПравойКнопки() и ПриНажатииКнопкиКлавиатуры() работают и в локальном контексте, т.е. необязательно их в ГМ помещать, можно прямо в модуль обработки

    Reply
  10. Noy

    (9) Так и планировал сразу — добавлять в модуль формы тех обработок/документов где это надо, а не в ГМ. Но для этого надо TurboMD, а Formex не дополняет локальные модули (или я плохо смотрел).

    Повторюсь — это пример реализации. Взять код из этой обработки, чуть-чуть подправить (убрать «ТекущийКонтекст») и добавить в нужные формы сможет любой, даже самый начинающий программист.

    Чего и хотелось достичь.

    Reply
  11. Abadonna

    Не поленился проверить что будет, если одна и та же процедура прописана в основном и дополнительном ГМ. Например,

    Процедура ПриНажатииЛевойКнопки(Конт,Состоян,КоординатаПоГоризонтали,КоординатаПоВертикали,ФСО);

    Получается так: сначала выполняется в основном глобальном модуле и тут же следом в ДопГМ.

    Reply
  12. Noy

    (11) хм… я чего-то решил, что будет ошибка при компиляции и даже не проверил. ну так даже лучше!

    Reply
  13. АЛьФ

    Вот проверять им не лень, а документацию по компоненте прочитать лень:

    Порядок поиска процедуры по имени:

    Процедура <РусскоеИмяПроцедуры>

    Процедура <АнглийскоеИмяПроцедуры>

    Функция <РусскоеИмяПроцедуры>

    Функция <АнглийскоеИмяПроцедуры>

    Порядок вызова

    Первоначально предопределенная процедура ищется в модуле активной формы.

    Если процедура присутствует в модуле формы, то она вызывается. В противном случае процедура ищется во всех загруженных глобальных модулях, в порядке их загрузки, начиная с основного глобального модуля.

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

    Reply
  14. Abadonna

    (13) АЛьФ, конечно же лень почитать ;))))))))))

    Reply
  15. Abadonna

    +(14) Проверял-то я ровно минуту, а прочитать и вникнуть — минуты 3 надо :))))

    Reply
  16. Noy

    (13) даа… а я и не прочитал и не проверил. Точнее читал, но запамятовал. Буду исправляться.

    P.S. Интересно — почему так происходит: чем больше «монстров-профессионалов» (в хорошем смысле этого слова и с глубоким уважением к выше высказавшимся) прокоментируют обработку, тем медленнее растет рейтинг???

    Reply
  17. Abadonna

    (16) Ну Альфовский можешь в уме на 10 как минимум помножить 😉

    Reply
  18. Noy

    (17) Уже заметил!

    (13) Спасибо!!! Действительно приятно.

    Reply
  19. vasilykushnir

    (13) Альф, ну же знаешь, что русский читает инструкцию только тогда, когда точно уверен, что сломал все, что можно было сломать. (:-).

    (16) Абадонна прав — Плюсики Альфа и ЧеБурашки дорогого стоят. Их отметки означают, что приблуда стОящая и можно качать спокойно.

    Reply
  20. Noy

    (19)+ ЧеБурашке вообще отдельное спасибо — всегда один из первых просмотрит, и почти всегда оставит комментарий.

    Reply
  21. Abadonna

    А локальном контексте (модуле обработки) можно сделать так

    Код
    Процедура ПриНажатииКнопкиКлавиатуры(код, альт, шифт, ФСО)
       ФормаРасш = СоздатьОбъект("РасширениеФормы");
       Атр=ФормаРасш.ПолучитьАтрибут(Форма.АктивныйЭлемент());
       Если ПустоеЗначение(Атр)=1 Тогда Возврат; КонецЕсли;    
       Если  ТипЗначенияСтр(Атр.Значение)="ТаблицаЗначений" Тогда
          Если Код=46 Тогда  // клавиша DEL  
             Атр.Значение.УдалитьСтроку();
          КонецЕсли; // и т.д. и т.п.      
       КонецЕсли;  
       ФормаРасш="";
    КонецПроцедуры
    
    Процедура ПриОтжатииЛевойКнопки(сост, х, у,ФСО)  
       ФормаРасш = СоздатьОбъект("РасширениеФормы");
       Атр=ФормаРасш.ПолучитьАтрибутПоКоординатам( х, у);
       Если ПустоеЗначение(Атр)=1 Тогда Возврат; КонецЕсли;
       Если  ТипЗначенияСтр(Атр.Значение)="ТаблицаЗначений" Тогда
          // чего-нибудь делаем с ТЗ
          ОбработкаСтроки();
          Инверсия();    
       КонецЕсли;  
       ФормаРасш="";
    КонецПроцедуры
    

    Показать полностью

    Reply
  22. strah4

    Удобно. Единственное что, куда более насущна возможность включать-выключать расширение из своего модуля обращением к процедуре глобального. Будет время прикручу обязательно. Спасибо большое!!! Тема очень мне нужная:)

    Reply
  23. Noy

    (22) Если будешь прикручивать — то делай не на всю конфигурацию, как у меня в примере, а на отдельные объекты и для каждого пользователя. Проверку сделай например через ПолныйТипОбъекта(). Ну и справочник с полями Пользователь, Форма, Сортировка (да/Нет), Удаление, Изменение и тд

    Имхо, так будет гораздо удобнее.

    Reply
  24. ge_ni

    Помогите!!! Не работает и не ругается! Растраска строк задействована! ПриОткрытии работает! Библиотеки зарегистрированы правильно и

    Reply
  25. maloi_a

    Замечания:

    1. Основные действия с ТЗ есть, а вставки строки нет, кроме того не работает с пустой таблицей.

    У меня надо было добавлять строку, я исправил — работает.

    2. Выходит ошибка, если кликнуть мышкой вне открытого окна или в окне сообщений:

    {Глобальный модуль(92)}: Значение не представляет агрегатный объект (Форма)

    ФормаРасш.УстановитьФорму(ТекущийКонтекст.Форма);

    Reply
  26. Noy

    (24) Напиши подробнее — что значит «не работает» и какая версия Formex?

    (25) 1. Ну это в принципе только пример, действий с ТЗ еще можно вагон прикрутить: добавление и сдвиг колонок и строк, отбор по значению, «свернуть», редактирование параметров колонок, использвание del (смотри комменнтарий 21), печать, сохранение настроек ширины и положения колонок в профиль и тд.

    2. Не предусмотрел 🙂 — надо было проверку поставить на ТипЗначенияСтр(ТекущийКонтекст).

    Спасибо за комментарий.

    Reply
  27. maloi_a

    Исправил ошибку (25) п. 2 следующим образом:



    |Процедура ПриОтжатииПравойКнопки(ТекущийКонтекст,Сост,х,у,ФСО)

    | ФормаРасш=СоздатьОбъект(«»РасширениеФормы»»);

    | Сообщить(ТекущийКонтекст);

    | Если ТекущийКонтекст<>»»ГрупповойКонтекст»» Тогда Возврат; КонецЕсли;

    | ФормаРасш.УстановитьФорму(ТекущийКонтекст.Форма);

    | Атр=ФормаРасш.ПолучитьАтрибутПоКоординатам(х,у);

    | Если ТипЗначенияСтр(атр)=»»АтрибутФормы»» Тогда

    | Если ТипЗначенияСтр(Атр.Значение)=»»ТаблицаЗначений»» Тогда

    | Если Атр.Идентификатор=ТекущийКонтекст.Форма.АктивныйЭлемент() тогда

    | ПравыйКликНаТЗ(ТекущийКонтекст,Атр.Значение);

    | КонецЕсли;

    | КонецЕсли;

    | КонецЕсли;

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

    |

    |»;

    ТекстГМОбработкаКлавы=»

    |

    |Процедура ПриНажатииКнопкиКлавиатуры(ТекущийКонтекст,Код,Алт,Шифт,Контрол,Символ,ФСО)

    | Сообщить(Код);

    | Если Код=93 Тогда

    | ФСО=0;

    | ФормаРасш=СоздатьОбъект(«»РасширениеФормы»»);

    | Сообщить(ТекущийКонтекст);

    | Если ТекущийКонтекст<>»»ГрупповойКонтекст»» Тогда Возврат; КонецЕсли;

    | ФормаРасш.УстановитьФорму(ТекущийКонтекст.Форма);

    | Атр=ФормаРасш.ПолучитьАтрибут(ТекущийКонтекст.Форма.АктивныйЭлемент());

    | Если ТипЗначенияСтр(атр)=»»АтрибутФормы»» Тогда

    | Если ТипЗначенияСтр(Атр.Значение)=»»ТаблицаЗначений»» Тогда

    | ПравыйКликНаТЗ(ТекущийКонтекст,Атр.Значение);

    | КонецЕсли;

    | КонецЕсли;

    | КонецЕсли;

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

    |»;

    После этого выявил следующую закономерность — мышиная и клавиатурная процедуры работают не всегда

    синхронно, а именно:

    1. Фокус на окне обработки — обе говорят «Групповой контекст».

    2. Если Фокус перенести с активного окна обработки хоть мышью, хоть клавиатурой,

    процедуры работают по-разному: клавиатурная — групповой контекст, мышиная — пусто.

    3. Фокус на окне сообщений — обе говорят пусто.

    4. Если Фокус перенести с окна сообщений, процедуры работают одинаково

    хоть в окне обработки, хоть вне окна.

    Вопрос к разработчикам?

    Reply
  28. Noy

    (27) Клава и мышь и не должны синхронно работать — как пример: выдели мышкой файл на рабочем столе, потом убери мышь например на кнопку пуск и нажми на клаве кнопку «контекстное меню». Тоесть клава «подвязывается» к активному элементу, а мышь к координатам, где произошло событие.

    В принципе можно добавить проверок и немного «выровнять» работу обработки.

    Reply
  29. ge_ni

    (24) FormEx 2.0.5.83 beta. Учитывая прикрученное к библиотеке описание все режимы должны поддерживаться. Регистрирую по 33labовски.

    Функция ЗагрузитьВК(стрИмяФайлаВК)

    Если ЗагрузитьВнешнююКомпоненту(_КаталогВнешнихКомпонент+стрИмяФайлаВК)=1 Тогда Возврат 1; КонецЕсли;

    СообщитьОбОшибкеЗагрузкиВК(стрИмяФайлаВК);

    Возврат 0;

    КонецФункции

    Функция ИнициализацияВнешнихКомпонент()

    Состояние(«Загрузка внешних компонент…»);

    Если ЗагрузитьВК(«1cpp.dll» )=0 Тогда Возврат 0; КонецЕсли;

    Если ЗагрузитьВК(«FormEx.dll» )=0 Тогда Возврат 0; КонецЕсли;

    Если ЗагрузитьВК(«DialMail.dll»)=0 Тогда Возврат 0; КонецЕсли;

    Если ЗагрузитьВК(«V7Plus.dll» )=0 Тогда Возврат 0; КонецЕсли;

    Если ЗагрузитьВК(«RWidjets.dll»)=0 Тогда Возврат 0; КонецЕсли;

    Если ЗагрузитьВК(«UsersDef.dll»)=0 Тогда Возврат 0; КонецЕсли;

    Если ЗагрузитьВК(«VTools.dll» )=0 Тогда Возврат 0; КонецЕсли;

    Чего ей не хватает?!

    Использую ряд классов

    и от 33lab и самописных. То что мне нужно, работает! А тут засада!

    Процедура ПриДвиженииМыши(конт, сост, х, у)

    Состояние(» х = » + х + » у = » + у + » сост = » + сост); //Не работает, даже не перехватывает

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

    Процедура ПриНажатииПравойКнопки(конт, сост, х, у)

    Сообщить(«Нажата правая кнопка мыши.»); //Не работает

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

    Может флаг какой выставил?! … или библиотеки мешают друг другу

    Reply
  30. Noy

    (29) Судя по всему с компонентой все ОК.

    В первую очередь проверь состояние Сервис.ПерехватКлавиатуры()=? и Сервис.ПерехватМыши()=? — оба значения должны быть равны 1.

    По поводу «мешают друг другу» — врядли, вот только я не работал с RWidjets и очень давно смотрел VTools. Можешь попробовать их отключить.

    Reply
  31. Abadonna

    (29)

    Функция ЗагрузитьВК(стрИмяФайлаВК)

    Если ЗагрузитьВнешнююКомпоненту(_КаталогВнешнихКомпонент+стрИмяФайлаВК)=1 Тогда Возврат 1; КонецЕсли;

    ____________________________________________________________­____

    Да уж!..; А написать просто:

    Возврат ЗагрузитьВнешнююКомпоненту(_КаталогВнешнихКомпонент+стрИмяФайлаВК);

    ??????? :))))))

    Reply
  32. ge_ni

    (31)Ну ладно уж!)) Текст-то не мой…, а исправлять вломы

    Reply
  33. ge_ni

    (30) Спасибо!!! Действительно Перехват мыши в 0!!! был Не доглядел. Еще раз спасибо

    Reply
  34. junglistizzy

    Интересное решение. Попробуем.

    спасибо!

    Reply
  35. dobraleks

    сенкс, поковыряю

    Reply

Leave a Comment

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