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




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

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

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

<?php // Полная загрузка сервисных книжек, создан 2026-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 не будет опубликован. Обязательные поля помечены *