При создании учебных или реальных конфигураций, таких как «Библиотека», начинающие разработчики часто сталкиваются с дилеммой: как хранить информацию о текущем местонахождении объекта. Распространенная ошибка — пытаться записывать данные о текущем арендаторе прямо в реквизиты справочника Книги. В этой статье мы разберем, почему такой подход неэффективен, и рассмотрим правильную архитектуру решения с использованием документов, регистров сведений и динамических списков.
Давайте проанализируем ситуацию: если мы записываем «Арендатора» непосредственно в реквизит справочника Книги, мы сталкиваемся с рядом технических сложностей. Во-первых, при каждом изменении статуса книги (выдана, возвращена) нам придется программно изменять объект справочника. Это приводит к блокировкам объекта, что в многопользовательской среде недопустимо. Во-вторых, мы полностью теряем историю перемещений книги — мы видим только последнего владельца, но не знаем, кто брал ее ранее. И, наконец, нам крайне сложно будет построить отчет о выдачах за период.
Рассмотрим правильную цепочку взаимодействия объектов в 1С: Документ — Регистр сведений — Динамический список. Именно эта связка позволяет реализовать все требования автора темы: и быстро видеть владельца, и отслеживать просрочку, и сохранять историю.
Вместо использования табличной части в справочнике Посетители, создадим документ ВыдачаКниги и периодический регистр сведений СостояниеКниг. Рассмотрим структуру регистра:
Книга (тип СправочникСсылка.Книги). Это ключевое поле, по которому мы будем искать информацию.Читатель (тип СправочникСсылка.Посетители).ПредполагаемаяДатаВозврата (тип Дата).Теперь, при проведении документа ВыдачаКниги, мы будем записывать данные в этот регистр. Это позволит нам всегда знать «Срез последних» данных — то есть текущее состояние каждой книги на любой момент времени.
Разберем вопрос автора о том, как получить ссылку на книгу при ее выборе в табличной части. Если вы работаете в форме документа, и вам нужно обработать изменение строки, используйте свойство ТекущиеДанные. Рассмотрим пример кода для обработчика события ПриИзменении в табличной части:
&НаКлиенте
Процедура СписокКнигКнигаПриИзменении(Элемент)
// Получаем строку, в которой произошло изменение
ТекущаяСтрока = Элементы.СписокКниг.ТекущиеДанные;
Если ТекущаяСтрока <> Неопределено Тогда
// Обращаемся к ссылке на книгу
ВыбраннаяКнига = ТекущаяСтрока.Книга;
// Здесь можно выполнить дополнительные действия, например,
// заполнить дату выдачи по умолчанию
ТекущаяСтрока.ДатаВыдачи = ТекущийДатуСеанса();
КонецЕсли;
КонецПроцедуры
Если же задача стоит в том, чтобы обойти всю таблицу при записи или проведении документа на сервере, проанализируем следующий цикл:
// В модуле объекта документа
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
Для Каждого СтрокаТЧ Из СписокКниг Цикл
// СтрокаТЧ.Книга — это и есть нужная нам ссылка
Запись = Движения.СостояниеКниг.Добавить();
Запись.Период = Дата;
Запись.Книга = СтрокаТЧ.Книга;
Запись.Читатель = Посетитель; // Реквизит шапки
Запись.ПредполагаемаяДатаВозврата = СтрокаТЧ.ДатаВозврата;
КонецЦикла;
КонецПроцедуры
Чтобы выполнить условие «в справочнике книг должна быть возможность быстро посмотреть, у кого на руках находится книга», не изменяя сам справочник, мы воспользуемся механизмом Динамического списка с произвольным запросом. Разберем, как это настроить в форме списка справочника Книги.
В свойствах списка установим флаг «Произвольный запрос» и напишем следующий текст запроса:
ВЫБРАТЬ
СправочникКниги.Ссылка КАК Ссылка,
СправочникКниги.Наименование КАК Наименование,
СправочникКниги.Автор КАК Автор,
СостояниеКнигСрезПоследних.Читатель КАК ТекущийДержатель,
СостояниеКнигСрезПоследних.ПредполагаемаяДатаВозврата КАК ДатаВозврата
ИЗ
Справочник.Книги КАК СправочникКниги
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СостояниеКниг.СрезПоследних(&Период, ) КАК СостояниеКнигСрезПоследних
ПО СправочникКниги.Ссылка = СостояниеКнигСрезПоследних.Книга
Благодаря ЛЕВОЕ СОЕДИНЕНИЕ, в списке отобразятся все книги. Если книга выдана — в колонке ТекущийДержатель будет указан человек, если книга в библиотеке — поле останется пустым. Это самый эффективный способ отображения оперативных данных.
Выясним, как помечать просроченные книги. Использовать для этого отдельный реквизит в базе данных — плохая практика, так как статус «Просрочена» зависит от текущей даты, которая меняется каждые сутки. Правильнее вычислять этот статус динамически.
Рассмотрим, как добавить визуальное выделение просроченных книг в списке. Для этого в настройках динамического списка (вкладка «Условное оформление») создадим новое правило:
ДатаВозврата меньше &ТекущаяДата И ТекущийДержатель заполнено.ДатаВозврата.Теперь администратор при открытии списка книг мгновенно увидит проблемные позиции без необходимости запускать отдельные отчеты.
Проанализируем ситуацию: что если администратор попытается выдать книгу, которая уже занята? Для этого в документе ВыдачаКниги перед записью или проведением необходимо добавить проверку. Мы должны обратиться к тому же регистру сведений и проверить наличие записи по конкретной книге.
Функция КнигаСвободна(ПроверяемаяКнига)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СостояниеКнигСрезПоследних.Читатель
|ИЗ
| РегистрСведений.СостояниеКниг.СрезПоследних(, Книга = &Книга) КАК СостояниеКнигСрезПоследних";
Запрос.УстановитьПараметр("Книга", ПроверяемаяКнига);
Результат = Запрос.Выполнить();
Если Результат.Пустой() Тогда
Возврат Истина; // Записей нет, книга в библиотеке
Иначе
Выборка = Результат.Выбрать();
Выборка.Следующий();
// Если читатель не заполнен (например, зафиксирован возврат), книга свободна
Возврат Не ЗначениеЗаполнено(Выборка.Читатель);
EndIf;
КонецФункции
Мы рассмотрели комплексный подход к решению задачи. Вместо хранения изменчивых данных в справочнике, мы создали надежную систему учета на базе регистров. Мы научились получать данные из табличных частей через ТекущиеДанные, настраивать динамические списки для отображения актуальных владельцев книг и использовать условное оформление для контроля просрочки. Такая архитектура является стандартной для профессиональной разработки на платформе 1С:Предприятие 8.3 и обеспечивает высокую производительность и масштабируемость вашего приложения.