Внешняя компонента для подсчета числа секунд простоя открытого сеанса 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='\

33 Comments

  1. sCHTASS

    Скажу про 1С77

    Для расчета простоя, как вариант, можно работать с предопределенным процедурами FormEx ПриДвиженииМыши() и ПриНажатииКнопкиКлавиатуры() через обработчик ожидания.

    Только сей алгоритм не работает, если 1С заблокирована или занята длительным процессом :((

    Reply
  2. coder1cv8

    Так есть же уже: http://infostart.ru/projects/2591/

    Reply
  3. artbear

    (2) В ВК 1С++ для 1С 77 эта проблему я давно решил, в ней есть метод, аналогичный сабжу.

    Reply
  4. bulpi

    2 coder1cv8

    Скачал, посмотрел. Действительно, все очень изящно. А для 7.7 как это применить?

    2 artbear

    1с++ — это здоровенный бронепоезд. А мне с него нужен один пулемет. Я не хочу ставить весь бронепоезд ради одного пулемета. Всем 1с плюс-плюсовцам — привет и мое уважение 🙂 !!!

    Reply
  5. artbear

    (4) А ты подумай над тем, что 1С++ дополнительно еще всякие полезные вещи делает 🙂

    Например, простая загрузка ВК 1С++ позволяет довольно ускорить работу всей 1С 🙂 и т.д. и т.п.

    Reply
  6. bulpi

    2 coder1cv8

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

    Reply
  7. kentavr27

    (3) В 1с++ есть именно аналогичная, но не такая. Представленная компонента дает возможность отслеживания бездействия именно в открытм сеансе 1С. (если 1С-ка свернута и пользователь шарится по рабочему столу — это бездействие. Только работа в 1С-ке сбрасывает счетчик). А в 1с++ счетчик сбрасывает ЛЮБОЕ действие в сеансе пользователя Win. Вот, собсвенно их отличие.

    Reply
  8. artbear

    (7) Вот с чего ты это взял про 1С++ ? 🙁

    Там как раз все реализовано через GetLastInputInfo() для текущего сеанса 1С.

    Reply
  9. kentavr27

    (8) С чего взял? Просто сам этим пользуюсь 🙂

    Не видел я в 1С++ GetLastInputInfo()

    там есть следующее:

    Информатор = СоздатьОбъект(«Информатор»);

    Информатор.ПолучитьВремяПростояСистемы();

    время простоя Win

    Reply
  10. monoteos

    Работает нормально, как раз недавно думал о такой компоненте. Автору респект

    Reply
  11. monoteos

    Вариант для вывода в удобном формате:

    Перем Компонент;

    Перем НачВремя;

    Процедура Проверить()

    ОбработкаПрерыванияПользователя();

    ТекПростой = Компонент.GetLastInputInfo();

    Если ТекПростой > 0 Тогда

    НачВремя = НачВремя + 1;

    Сообщить(Строка(ТекПростой) + » секунд, » + Формат(НачВремя,»ДФ=ЧЧ:мм:сс»));

    КонецЕсли;

    ПодключитьОбработчикОжидания(«Проверить»,1,Истина);

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

    Процедура ПриОткрытии()

    НачВремя = Дата(«00010101000000»);

    ЗагрузитьВнешнююКомпоненту(«NoSlip.dll»);

    Компонент = Новый(«AddIn.NoSlipAddInExtension»);

    ПодключитьОбработчикОжидания(«Проверить»,1,Истина);

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

    Reply
  12. skom

    Перем СтарыйПростой, НовыйПростой;

    Перем Компонент;

    Процедура Простой()

    СтарыйПростой = НовыйПростой;

    НовыйПростой = Компонент.GetLastInputInfo();

    Сообщить(СтарыйПростой + » сек»);

    Сообщить(НовыйПростой + » сек. прост. новый»);

    Сообщить(«====================»);

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

    Процедура ПриОткрытии()

    ЗагрузитьВнешнююКомпоненту(«NoSlip.dll»);

    Компонент = СоздатьОбъект(«AddIn.NoSlipAddInExtension»);

    Форма.ОбработкаОжидания(«Простой»,10);

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

    СтарыйПростой = 0;

    НовыйПростой = 0;

    вот такая обработка выдает вот такие результаты

    АВТОР с чем это связано?

    неужели так долго работает Сообщить()

    //результат

    1

    2

    ====================

    2

    15

    ====================

    15

    27

    ====================

    27

    39

    ====================

    39

    51

    ====================

    51

    63

    ====================

    63

    76

    ====================

    76

    88

    ====================

    88

    100

    Reply
  13. skom

    вызов через 10 сек

    разницу выдает от 12 или 13 сек

    Reply
  14. bulpi

    2 skom (12,13)

    ИМХО, это так долго работает

    Форма.ОбработкаОжидания(«Простой»,10);

    Я думаю, 1с периодически опрашивает все открытые формы, не пора ли их обновить, с интервалом в несколько секунд. Именно тогда и проверяется, не пора ли запустить обработку ожидания. Поэтому она запускается не точно через 10 сек, а 10+ какой-то кусок интервала опроса. Возможно, на этот интервал можно повлиять через Сервис — Параметры — Период опроса изменений базы данных (сек).

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

    Reply
  15. skom

    можешь в аську

    333138647

    Reply
  16. skom

    Процедура глПроверкаПростоя()

    СистемноеВремяПростоя = Константа.ВремяПростоя;

    СтароеВремяПростоя = глВремяПростоя;

    глВремяПростоя = ЗамерВремениПростоя.GetLastInputInfo();

    Если глВремяПростоя-СтароеВремяПростоя < 30 Тогда

    ТочноеВремяПростоя = глВремяПростоя;

    Если ТочноеВремяПростоя/60 >= СистемноеВремяПростоя Тогда

    Часов = Цел(ТочноеВремяПростоя/3600);

    Минут = Цел(ТочноеВремяПростоя/60)-Часов*60;

    Секунд = ТочноеВремяПростоя — Минут*60-Часов*3600;

    ЗаписьЖурналаРегистрации(«Простой системы составил «+Часов+» часов «+Минут+» мин. » +Секунд+» сек.»,,»Простой системы»);

    Запрос=СоздатьОбъект(«ODBCRecordSet»);

    //——————А теперь добавляем————————————-

    ДатаТек=Формат(ТекущаяДата(), «ДГГГГММДД»);

    ТекстЗапроса = «ins ert into SleepTime values(‘»+ИмяПользователя()+»‘, «+ТочноеВремяПростоя+», «+ДатаТек+», «+ТекущееВремя()+»)»;

    Если Запрос.Выполнить(ТекстЗапроса)=0 Тогда

    Сообщить(Запрос.ПолучитьОписаниеОшибки());

    Конецесли;

    //обнулим счетчик простоя

    глВремяПростоя = 0;

    КонецЕсли;

    КонецЕсли;

    КонецПроцедуры // глПроверкаПростоя

    эта процедура запускается раз в 30 сек

    для теста стоит 2 минуты

    но не срабатывает

    Reply
  17. skom

    у меня все в глобальнике открывается

    процедура в глобальнике

    и обработка ожидания из формекса. которой пофигу на модальные окна

    Reply
  18. bulpi

    (16)

    Аськи у меня нет, я ее не люблю.

    Не срабатывает, имхо, из-за странного условия

    Если глВремяПростоя-СтароеВремяПростоя < 30 Тогда

    Что ты этим хотел добиться?

    Убери его , и заработает.

    Не в тему : а что это такое странное ты делаешь с помощью объекта ODBCRecordSet ?

    Reply
  19. skom

    ODBCRecordSet — это в скульную таблицу записываю инфу о простое системы

    глВремяПростоя-СтароеВремяПростоя < 30

    это условие надо для того что бы не каждый например час записывать инфу о бездействии пользователя

    а например если он 2 часа и 30 сек не действует то по после того как он задействовал записалось что бы

    так вот

    обработка ожидания в рабочей базе у меня запускается с интервалом в 30 сек

    сначала запоминается предыдущее значение простоя

    например 100 сек. потом вычисляется последнее значение простоя

    например если бездействие тогда оно составит 30 сек и тогда получим

    130-100 < 30

    тогда в данном случае не пишем в лог так как бездействие ПРОДОЛЖАЕТСЯ

    а если в течении этих 30 сек пользователь что то сделает тогда получим

    120-100< 30

    тогда получается что пользователь прервал бездействие

    и вот тут и надо записать в лог сколько он бездействовал

    Reply
  20. bulpi

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

    Reply
  21. skom

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

    а на боевой рабочей базе получаются глюки.

    чел работает. а система пишет простой работы

    а в этой верный алгоритм но не работает)) вот так.

    Reply
  22. skom

    кстати код не совсем верный

    надо дополнять

    ибо если например человек пришел утром запустил систему

    и ушел

    а в обед сессию рубанули

    то в системе не запишется простой системы.

    Reply
  23. bulpi

    (22)

    Возможно, стоит записывать 2 события — начало простоя (если простой превышает N минут) и конец простоя. А если конец не записан, значит концом простоя является выход из системы.

    Reply
  24. a_mironov

    Процедура глПроверкаПростоя()

    СистемноеВремяПростоя = Константа.ВремяПростоя;

    СтароеВремяПростоя = глВремяПростоя;

    глВремяПростоя = ЗамерВремениПростоя.GetLastInputInfo();

    Если глВремяПростоя-СтароеВремяПростоя < 30 Тогда

    ТочноеВремяПростоя = глВремяПростоя;

    Если ТочноеВремяПростоя/60 >= СистемноеВремяПростоя Тогда

    Часов = Цел(ТочноеВремяПростоя/3600);

    Минут = Цел(ТочноеВремяПростоя/60)-Часов*60;

    Секунд = ТочноеВремяПростоя — Минут*60-Часов*3600;

    ЗаписьЖурналаРегистрации(«Простой системы составил «+Часов+» часов «+Минут+» мин. » +Секунд+» сек.»,,»Простой системы»);

    Запрос=СоздатьОбъект(«ODBCRecordSet»);

    //——————А теперь добавляем————————————-

    ДатаТек=Формат(ТекущаяДата(), «ДГГГГММДД»);

    ТекстЗапроса = «ins ert into SleepTime values(‘»+ИмяПользователя()+»‘, «+ТочноеВремяПростоя+», «+ДатаТек+», «+ТекущееВремя()+»)»;

    Если Запрос.Выполнить(ТекстЗапроса)=0 Тогда

    Сообщить(Запрос.ПолучитьОписаниеОшибки());

    Конецесли;

    //обнулим счетчик простоя

    глВремяПростоя = 0;

    КонецЕсли;

    КонецЕсли;

    КонецПроцедуры // глПроверкаПростоя

    эта процедура запускается раз в 30 сек

    для теста стоит 2 минуты

    но не срабатывает

    Reply
  25. dyak84

    Автор а как он работает как он определяет вернее сказать по какому принципу время простоя.

    Reply
  26. bulpi

    (25)

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

    Reply
  27. smaharbA

    ОбработкаОжидания(«ОпределениеПростоя»,1);

    как использовать обработку ожидания не для одного действия все знают

    Reply
  28. DeniNikitin

    А можно тоже самое только чтобы считал не для окна 1С а для системы?

    Reply
  29. bulpi

    Вот здесь было : http://infostart.ru/projects/2591/

    А мне это не интересно, я хотел именно в 1с считать секунды.

    Reply
  30. DeniNikitin

    Платформа: 8.2.19.76

    Конфигурация:Управление производственным предприятием, редакция 1.3 (1.3.36.1)

    При открытии вашей обработки:

    {Форма.Форма.Форма(20)}: Ошибка при вызове метода контекста (ЗагрузитьВнешнююКомпоненту)

    ЗагрузитьВнешнююКомпоненту(«NoSlip.dll»);

    по причине:

    Ошибка при загрузке внешней компоненты

    Пробовал и через подключитьвнешнююкомпоненту тоже не получилось!

    Reply
  31. bulpi

    (30)

    Это проблема с правами в системе. Нужно 1 раз войти как админ, выполнить метод ЗагрузитьВнешнююКомпоненту, чтобы в реестре прописались ключи, а затем ее смогут использовать и пользователи без прав админа. Подробно написано здесь http://kb.mista.ru/article.php?id=419

    Reply
  32. CaSH_2004

    (0)Автор уточни плиз как понимать то что в статье указано

    …моя внешняя компонента не требует регистрации…

    а потом ты в (31) пишеш:

    Нужно 1 раз войти как админ, выполнить метод ЗагрузитьВнешнююКомпоненту, чтобы в реестре прописались ключи

    я уж подумал что у вас ВК по технологии Native API написана, а теперь сомневаюсь вот…

    Не подскажите направление куда копать чтобы добится эффекта работы только в окне 1С? я АПИ не силен. но наваял аналог в 1С напрямую используя DynamicWrapperX

    Reply
  33. bulpi

    (32)

    Не требует регистрации в том смысле, что не нужно писать regsvr32 NoSlip.dll

    Когда я это делал, в 1с технологии Native API не существовало.

    «куда копать чтобы добится эффекта работы только в окне 1С?»

    Исходники могу выслать.

    Reply

Leave a Comment

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