Книга знаний

1С:Предприятие / Объекты конфигурации / Документы

v7: Кто открыл документ

Как определить кто блокировал конкретный документ /v7/ Автор статьи: Z1 | Редакторы: Волшебник
Последняя редакция №6 от 10.07.06 | История
URL: http://kb.mista.ru/article.php?id=246

Ключевые слова: 1с++, mssql, блокировка, документ, открыл


Пролог



Для больших 1с приложением когда пользователей больше 50 начинают очень
часто возникать проблемы как узнать кто открыл документ(справочник).

Обычно как всегда все происходит в самый неподходящий момент (законы Мерфи):
Клиент звонит менеджеру.Менеджер хочет внести небольшое изменение в счет( сделка
очень важная с хорошим клиентом на хорошую сумму) и обнаруживает что его счет
кто-то заблокировал. клиент висит на телефоне, домумент не открывается,
сделка под угрозой, менеджер в бешенстве.


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

Постановка задачи


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

Поводом для написания статьи послужило:
"ОФФ: Прототип статьи. Решение проблемы файловых блокировок в 1С 7.7"
http://abelov.com/forum/f.php?ak=29369&pg=-1

Решение



Решение основана на 1с++. При начале работе 1с программы необходимо загрузить 1с++.
(Кому не нравиться 1с++ можно переписать через ado ).

В глобальном модуле надо добавить:

Функция SQLКтоОткрыл( ТекущЗнач)     Экспорт
    Если ПустоеЗначение(ТекущЗнач) = 1 Тогда Сообщить("Не выбрано значение");return 1; КонецЕсли;
    meta1 = СоздатьОбъект("MetaDataWork");
    rc = СоздатьОбъект("ODBCRecordSet");
    Зн1 = "'" + meta1.ЗначениеВДлиннуюСтрокуБД(ТекущЗнач) + "'";
    Стр_0 = "SELECT who,comp, convert( char,date, 113)  from users_1c where id = " + Зн1;
    Табл_2 = СоздатьОбъект("ТаблицаЗначений");
    Табл_2.НоваяКолонка("Кто","Строка");
    Табл_2.НоваяКолонка("Комр","Строка");
    Табл_2.НоваяКолонка("ДатаВремя","Строка");

    rc.Открыть(Стр_0, 0,0);
    rc.УстТипыКолонок1С("Строка,Строка,Строка");
    Попытка
        rc.ПолучитьРезультатыВ_ТЗ(Табл_2,0 );
        
    Исключение
        Сообщить("не удалось обратиться к users_1c");
        return 0;
    КонецПопытки;
    rc.Закрыть();
    Если Табл_2.КоличествоСтрок() <= 0 Тогда
        Сообщить("Объект никем не занят !!!");
        return 1;
    КонецЕсли;
        
    Стр_1 = сокрЛП(Табл_2.ПолучитьЗначение(1,"Кто"));
    Стр_2 = сокрЛП(Табл_2.ПолучитьЗначение(1,"Комр"));
    Стр_3 = сокрЛП(Табл_2.ПолучитьЗначение(1,"ДатаВремя"));
    Сообщить("" + Стр_1 + " комп " + Стр_2 + " открыл " + Стр_3);
    return 1;
КонецФункции

Функция SQLОткрытьДокумент( Конт)  Экспорт
//create table users_1c
//( 
//  id   char (13),
//  who  char (50),
//  comp char (50),
//  date datetime,
//  primary key (id)
//)
    Если Конт.Форма.ТолькоПросмотр() = 1 Тогда
        return 1;
    КонецЕсли;
    
    ТекДок = Конт.ТекущийДокумент();
    Если ПустоеЗначение(ТекДок) = 1 Тогда return 1; КонецЕсли;
    
    //Сообщить("ТекДок " + СокрЛП(ТекДок.НомерДок) + " от " + ТекДок.ДатаДок );
    meta1 = СоздатьОбъект("MetaDataWork");
    rc = СоздатьОбъект("ODBCRecordSet");
    Зн1 = "'" + meta1.ЗначениеВДлиннуюСтрокуБД(ТекДок) + "'";
    Зн2 = "'" + ИмяПользователя() + "'";
    Зн3 = "'" + ИмяКомпьютера() + "'";
    Стр_0 = "insert into users_1c ( id, who, comp, date) " +
    " values ( " + Зн1 + "," + Зн2 + "," + Зн3 + "," + "GETDATE() )";
    СделатьUpdate = 0;
    Попытка
        rc.Выполнить(Стр_0);
    Исключение
        СделатьUpdate = 1;
    КонецПопытки;    
    Если СделатьUpdate = 1 Тогда
        Стр_0 = "update users_1c  set  who = " + Зн2 + ", comp = " + Зн3 + " , date = GETDATE() " +   
        " where id = " + Зн1;
        Попытка
            rc.Выполнить(Стр_0);
        Исключение
            Сообщить("не смогли update ");
        КонецПопытки;    

    КонецЕсли;

    return 1;
КонецФункции    

Функция SQLЗакрытьДокумент( Конт)  Экспорт
    ТекДок = Конт.ТекущийДокумент();
    Если ПустоеЗначение(ТекДок) = 1 Тогда return 1; КонецЕсли;
    
    //Сообщить("ТекДок " + СокрЛП(ТекДок.НомерДок) + " от " + ТекДок.ДатаДок );
    meta1 = СоздатьОбъект("MetaDataWork");
    rc = СоздатьОбъект("ODBCRecordSet");
    Зн1 = "'" + meta1.ЗначениеВДлиннуюСтрокуБД(ТекДок) + "'";
    Стр_0 = "delete  from users_1c where  id = " + Зн1;
    Попытка
        rc.Выполнить(Стр_0);
    Исключение
    КонецПопытки;    
    return 1;

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



В каждом документе(спраовчнике) в модуле ПриОткрытии() необходимо добавить :
   
SQLОткрытьДокумент( Контекст);

В каждом документе(спраовчнике) в модуле ПриЗакрытии() необходимо добавить :
   
SQLЗакрытьДокумент( Контекст);

На кнопке в журнале документов кнопка. на кнопке функция
SQLКтоОткрыл( ТекущийДокумент)


Вроде все.

Таблица users_1c размещается в базе 1с ( можно разместить и в другой sql бд непринципиально)
параметры sql таблицы :

create table users_1c
( 
  id   char (13),
  who  char (50),
  comp char (50),
  date datetime,
  primary key (id)
)


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

Дальнейшее развитие



1. Все вышеизложенное можно адаптировать для 1с dbf версии.
2.Решение задачи запретить сохранять док через n минут) после всего вышеизложенного достаточно
тривиальная задача и оставлена в качестве упражнения.
3. Если в этом есть необходимость решение легко адаптируется и для v8.

Недостаток вышеизложенного. Если 1с приложение по каким либо причинам "упало"
то таблица  users_1c не учитывает это.
Это можно улучшить следущим образом :
В таблицу user_1c добавляем  два столбца spid,hostname.
Во время insert эти столбцы заполняем.  
Во время выполнения отчетов ( у меня ктооткрыл )
Делаем нулевой шаг удаляем из таблицы user_1c все строки несуществующих
процессов.
т.е если в таблице user_1c есть <SPID1>, <HOSTNAME1>
и не существует такого значения  <SPID1>, <HOSTNAME1>  
в таблице master.dbo.sysprocesses (nolock)  то эту строку удаляем из user_1c ( эта строка соответсвует свернувшимуся 1с приложению




Эпилог



Надеюсь, статья была полезной и Вы не зря потратили свое время, дочитав до этих строк.

Принимаются любые пожелания,коментарии, предложения, критика и.т.д.
02.06.2006 г.
с уважением Морев Андрей  aka Z1

Описание | Рубрикатор | Поиск | ТелепатБот | Захваченные статьи | Установки | Форум
© Станислав Митичкин (Волшебник), 2005-2025 | Mista.ru

Яндекс.Метрика