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