Как скрыть выбранный документ из списка для других пользователей в 1С

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

Постановка задачи и выбор стратегии решения

Представим ситуацию: у нас есть обработка, на первом шаге которой отображается список документов. Как только пользователь №1 выбирает документ для работы, этот объект должен стать невидимым для пользователя №2, открывшего ту же обработку. При этом мы должны учитывать риск некорректного завершения сеанса (отключение света, зависание компьютера), чтобы документ не остался «заблокированным» навсегда.

Проанализируем возможные варианты реализации:

  1. Объектная блокировка: Использование метода ЗаблокироватьДанныеДляРедактирования(). Метод хорош тем, что платформа сама снимает блокировку при закрытии формы или падении сеанса. Однако он предназначен скорее для редактирования, а не для логического «скрытия» из списков.
  2. Добавление реквизита в документ: Создание признака ДокументВыбран непосредственно в объекте. Это не элегантно, так как требует изменения структуры метаданных и может привести к лишним блокировкам при записи самого документа.
  3. Использование регистра сведений: Это наиболее гибкий и профессиональный подход. Мы будем записывать данные о «захвате» в отдельный независимый регистр.

Шаг 1: Создание вспомогательного регистра сведений

Для начала нам необходимо создать независимый Регистр Сведений (назовем его ЗанятыеДокументы). Рассмотрим оптимальную структуру этого регистра:

Шаг 2: Реализация механизма захвата при выборе документа

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

Рассмотрим пример кода для записи в регистр:


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

Шаг 3: Настройка динамического списка

Теперь выясним, как скрыть эти документы из общего списка. В динамическом списке на форме обработки нам нужно изменить текст запроса. Мы добавим ЛЕВОЕ СОЕДИНЕНИЕ с нашим новым регистром и установим условие, что запись в регистре должна отсутствовать.

Проанализируем пример запроса для динамического списка:


ВЫБРАТЬ
    Док.Ссылка КАК Ссылка,
    Док.Номер КАК Номер,
    Док.Дата КАК Дата
ИЗ
    Документ.ЗаказПокупателя КАК Док
ЛЕВОЕ СОЕДИНЕНИЕ 
    РегистрСведений.ЗанятыеДокументы КАК Занятые
ПО 
    Док.Ссылка = Занятые.Объект
ГДЕ
    Занятые.Объект ЕСТЬ NULL
    И Док.Проведен = ИСТИНА

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

Шаг 4: Освобождение документа и обработка зависших сессий

Чтобы система работала корректно, мы должны очищать записи в регистре, когда пользователь заканчивает работу. Рассмотрим основные сценарии:

  1. Штатное завершение: В событии формы ПриЗакрытии или ПередЗакрытием необходимо вызвать серверную процедуру, которая удалит запись из регистра ЗанятыеДокументы по фильтру ИдентификаторФормы.
  2. Механизм Heartbeat (Пульсация): Для повышения надежности мы можем внедрить «пульсацию». На форме настраивается ПодключитьОбработчикОжидания, который раз в минуту обновляет ДатаЗахвата в регистре. Это подтверждает системе, что пользователь всё еще активно работает с документом.
  3. Регламентное задание: Настроим регламентное задание, которое прочесывает регистр раз в несколько минут. Если ДатаЗахвата отличается от текущего времени более чем на 5–10 минут (и не обновлялась «пульсацией»), значит сеанс завершился некорректно, и запись можно удалять.

Рассмотрим пример кода для регламентного задания очистки:


Процедура ОчиститьПодвисшиеЗахваты() Экспорт
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Занятые.Объект КАК Объект
        |ИЗ
        |   РегистрСведений.ЗанятыеДокументы КАК Занятые
        |ГДЕ
        |   Занятые.ДатаЗахвата < &КритическаяДата";
    
    // Считаем захват подвисшим, если он старше 10 минут
    Запрос.УстановитьПараметр("КритическаяДата", ТекущаяДатаСеанса() - 600); 
    
    Выборка = Запрос.Выполнить().Выбрать();
    
    Пока Выборка.Следующий() Цикл
        Набор = РегистрыСведений.ЗанятыеДокументы.СоздатьНаборЗаписей();
        Набор.Отбор.Объект.Установить(Выборка.Объект);
        Набор.Записать();
    КонецЦикла;
    
КонецПроцедуры

Альтернатива: Использование Системы взаимодействия

Если в вашей конфигурации внедрена Система взаимодействия, мы можем сделать механизм еще более современным. При захвате документа пользователем №1, сервер может отправить фоновое сообщение всем остальным открытым формам. Получив такое сообщение, форма пользователя №2 может автоматически обновить динамический список или просто пометить строку серым цветом, не дожидаясь действий пользователя. Это обеспечивает максимальную интерактивность интерфейса.

Резюме

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

← На главную