Как изменить статус элемента справочника при проведении документа в 1С

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

При разработке конфигураций в 1С часто возникает задача отражения состояния объекта: например, когда при проведении документа бронирования номер в отеле должен помечаться как занятый, а при отмене проведения — освобождаться. Рассмотрим, почему при попытке прямого изменения справочника возникает ошибка, как её исправить и какой архитектурный подход является наиболее надежным.

Причина ошибки «Значение не является значением объектного типа (ПолучитьОбъект)»

Разберем типичный фрагмент кода в модуле объекта документа, который приводит к ошибке:


Процедура ОбработкаПроведения(Отказ, Режим)
    Ном = Номер.ПолучитьОбъект();
    Ном.Забронирован = Истина;
    Ном.Записать();
КонецПроцедуры

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

Также ошибка возникает в ситуации, когда реквизит-ссылка на справочник не заполнен (содержит Неопределено или пустую ссылку).

Разберем по шагам, как исправить прямое обращение к справочнику:

  1. Переименуем пользовательский реквизит документа во избежание конфликта имен (например, в НомерОтеля, Комната или НомерКомнаты).
  2. Добавим проверку заполненности реквизита перед получением объекта.
  3. Обязательно предусмотрим обработчик отмены проведения документа.

Посмотрим на исправленный код модуля документа:


Процедура ОбработкаПроведения(Отказ, Режим)
    Если ЗначениеЗаполнено(ЭтотОбъект.НомерОтеля) Тогда
        ОбъектНомера = ЭтотОбъект.НомерОтеля.ПолучитьОбъект();
        Если ОбъектНомера <> Неопределено Тогда
            ОбъектНомера.Забронирован = Истина;
            ОбъектНомера.Записать();
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Процедура ОбработкаУдаленияПроведения(Отказ)
    Если ЗначениеЗаполнено(ЭтотОбъект.НомерОтеля) Тогда
        ОбъектНомера = ЭтотОбъект.НомерОтеля.ПолучитьОбъект();
        Если ОбъектНомера <> Неопределено Тогда
            ОбъектНомера.Забронирован = Ложь;
            ОбъектНомера.Записать();
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Почему прямое изменение справочника из документа — не лучшее решение

Проанализируем технические проблемы, к которым приводит хранение статуса непосредственно в реквизите справочника:

  1. Коллизии при одновременной работе нескольких документов: если для одного номера создано несколько документов бронирования на разные даты, проведение или отмена проведения одного документа перезапишет общий статус номера независимо от других броней.
  2. Блокировки данных и конфликты версий: при программной записи справочника из транзакции документа накладываются транзакционные блокировки. Если пользователь в этот момент держит открытой форму элемента справочника, при сохранении он получит ошибку несоответствия версии объекта.
  3. Отсутствие истории и интервальности: реквизит справочника может хранить только одно текущее состояние и не позволяет планировать занятость по датам вперед.

Рекомендуемое решение: использование регистра сведений

Для учета статусов и занятости в платформе 1С предназначен объект метаданных Регистр сведений. Рассмотрим правильную реализацию задачи через регистр сведений, подчиненный регистратору.

Разберем создание структуры данных по шагам:

  1. Создаем периодический регистр сведений СтатусыНомеров с режимом записи Подчинение регистратору.
  2. В регистре создаем измерение НомерОтеля (тип СправочникСсылка.НомераОтеля) и ресурс Занят (тип Булево) или Статус (тип ПеречислениеСсылка.СтатусыНомеров).
  3. В свойствах документа бронирования указываем созданный регистр на вкладке Движения.

Посмотрим на пример формирования движений в модуле документа:


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

Важное преимущество: при использовании движений по регистру платформенный механизм 1С автоматически очищает движения при отмене проведения документа. Программисту не требуется писать ручной код очистки в событии ОбработкаУдаленияПроведения.

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

Чтобы пользователи видели актуальный статус занятости в форме списка справочника, не нужно менять реквизиты самого справочника. Достаточно подключить регистр через запрос в свойствах динамического списка формы.

Разберем настройку запроса динамического списка:

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

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


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

В модуле формы в обработчике ПриСозданииНаСервере передаем текущую дату в параметры списка:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    Список.Параметры.УстановитьЗначениеПараметра("ТекущаяДата", ТекущаяДатаСеанса());
КонецПроцедуры

После этого поле Занят можно вынести в колонки таблицы на форме и настроить условное оформление (например, выделение занятых номеров другим цветом текста или фона), сохранив при этом чистоту архитектуры и быстродействие базы данных.

← На главную