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

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

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

Введение: Почему не стоит напрямую изменять справочник?

Начнем с анализа первоначальной задачи: "При проведении документа ВыдачаКниги, в справочник Книги в реквизит Статус записывалось "Выдана"". На первый взгляд это может показаться простым решением, но опытные разработчики 1С справедливо указывают, что прямое изменение реквизита справочника при проведении документа является плохой практикой. Рассмотрим подробнее причины:

  1. Нарушение принципа разделения данных: Справочники в 1С предназначены для хранения условно-постоянной, справочной информации об объектах (например, название книги, автор, ISBN). Оперативные данные, которые постоянно меняются в результате действий пользователя (например, текущий статус или местонахождение книги), должны храниться в других объектах, таких как регистры.
  2. Проблемы с историей и отчетностью: При прямом изменении реквизита "Статус" он будет просто перезаписываться. Мы не сможем узнать, когда именно книга была выдана, кому, когда возвращена, или какой у нее был статус на произвольный момент времени в прошлом. Для получения такой истории потребуются значительные доработки.
  3. Проблемы с многопользовательской работой: В многопользовательской среде попытки одновременного изменения одного и того же элемента справочника могут привести к блокировкам, ошибкам или потере данных. Регистры же оптимизированы для интенсивной записи и чтения данных.
  4. Невозможность получения остатков/статуса на произвольный момент времени: Если нам потребуется узнать, сколько книг было выдано на определенную дату в прошлом, или какие книги были доступны, прямой реквизит справочника не даст этой информации. Регистры специально созданы для таких запросов.

Поэтому мы с вами будем искать более правильный, архитектурно верный и гибкий подход.

Правильный подход: Использование регистров 1С

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

  1. Регистр сведений (РС): Если нам нужно хранить актуальный статус каждой уникальной книги (экземпляра) и при этом иметь возможность просматривать историю его изменений. Регистр сведений может быть периодическим, что позволяет отслеживать изменения данных на определенные даты.
  2. Регистр накоплений (РН): Если нам нужно вести количественный учет экземпляров книг, их движение (поступление, выдача, возврат) и получать остатки на складах, в фондах или на руках у читателей. Это более мощный инструмент для учета движения объектов.

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

Регистр накоплений для учета экземпляров книг (рекомендуемый подход)

Регистр накоплений типа "Остатки" идеально подходит для нашей задачи. Он позволит нам:

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

Структура данных для учета

Прежде чем перейти к реализации, определим необходимую структуру данных в нашей конфигурации 1С:

  1. Справочник Книги: Мы будем использовать этот справочник для хранения информации об уникальных экземплярах книг. Это означает, что каждый элемент справочника Книги будет соответствовать одной физической копии книги. В этом справочнике будут храниться такие метаданные, как Название, Автор, ISBN, ГодИздания, а также критически важный реквизит ИнвентарныйНомер, который будет уникально идентифицировать каждый экземпляр.
  2. Справочник Читатели: Этот справочник будет хранить информацию о лицах, которым выдаются книги (ФИО, контактные данные и т.п.).
  3. Документ ВыдачаКниги: Этот документ будет регистрировать факт выдачи одной или нескольких книг читателю.
  4. Документ ВозвратКниги: Этот документ будет регистрировать факт возврата книги от читателя в библиотеку.
  5. Перечисление МестаХраненияКниг: Для удобства мы создадим перечисление со значениями, такими как "Библиотека", "НаРукахУЧитателя", "ВРемонте", "НаРеставрации" и т.п.
  6. Регистр накоплений НаличиеКниг: Этот регистр будет хранить оперативную информацию о текущем местонахождении каждого экземпляра книги.

Создание Регистра накоплений НаличиеКниг

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

Не забудьте установить для документа ВыдачаКниги и ВозвратКниги (который мы создадим позже) признак "Регистратор" для регистра НаличиеКниг.

Модификация документа ВыдачаКниги

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

Пример кода в обработке проведения документа ВыдачаКниги

В обработчике проведения документа ВыдачаКниги (процедура ОбработкаПроведения()) мы будем формировать движения по регистру накоплений НаличиеКниг. Предположим, что в документе есть табличная часть ВыдаваемыеКниги, которая содержит колонки Книга и Читатель.


Процедура ОбработкаПроведения(Отказ, РежимПроведения)

    // Устанавливаем режим записи движений для регистра НаличиеКниг
    Движения.НаличиеКниг.Записывать = Истина;
    // Очищаем существующие движения, если документ перепроводится
    Движения.НаличиеКниг.Очистить();

    Для Каждого СтрокаТЧ Из ВыдаваемыеКниги Цикл
        // Шаг 1: Проверяем, что книга доступна в библиотеке
        // Мы используем запрос к виртуальной таблице остатков регистра
        // для проверки наличия книги в нужном месте.
        Запрос = Новый Запрос;
        Запрос.Текст = 
            "ВЫБРАТЬ ПЕРВЫЕ 1
            |    НаличиеКнигОстатки.Книга КАК Книга,
            |    НаличиеКнигОстатки.КоличествоОстаток КАК Количество
            |ИЗ
            |    РегистрНакоплений.НаличиеКниг.Остатки(
            |        &МоментВремени,
            |        Книга = &Книга
            |            И МестоНахождения = &МестоНахожденияВБиблиотеке
            |    ) КАК НаличиеКнигОстатки";
        Запрос.УстановитьПараметр("МоментВремени", МоментВремени()); // Момент времени проведения документа
        Запрос.УстановитьПараметр("Книга", СтрокаТЧ.Книга);
        Запрос.УстановитьПараметр("МестоНахожденияВБиблиотеке", Перечисления.МестаХраненияКниг.Библиотека);

        РезультатЗапроса = Запрос.Выполнить();
        Выборка = РезультатЗапроса.Выбрать();

        Если НЕ Выборка.Следующий() Тогда
            // Если книга не найдена в библиотеке, значит ее там нет или она уже выдана
            Отказ = Истина;
            Сообщить("Экземпляр книги " + СтрокаТЧ.Книга.ИнвентарныйНомер + " ('" + СтрокаТЧ.Книга.Наименование + "') отсутствует в библиотеке или уже находится не в фонде!");
            Продолжить; // Переходим к следующей строке табличной части
        КонецЕсли;

        // Если книга найдена, и ее количество (для пообъектного учета это 1) больше 0,
        // то мы можем ее выдать.

        // Шаг 2: Формируем движения регистра
        // Движение Расход: книга выбывает из библиотеки
        Движение = Движения.НаличиеКниг.Добавить();
        Движение.ВидДвижения = ВидДвиженияНакопления.Расход; // Книга выбывает
        Движение.Период = Дата; // Дата документа
        Движение.Книга = СтрокаТЧ.Книга;
        Движение.МестоНахождения = Перечисления.МестаХраненияКниг.Библиотека;
        Движение.Количество = 1; // Учитываем по экземплярам

        // Движение Приход: книга поступает читателю
        Движение = Движения.НаличиеКниг.Добавить();
        Движение.ВидДвижения = ВидДвиженияНакопления.Приход; // Книга прибывает к читателю
        Движение.Период = Дата;
        Движение.Книга = СтрокаТЧ.Книга;
        Движение.МестоНахождения = Перечисления.МестаХраненияКниг.НаРукахУЧитателя;
        Движение.Читатель = СтрокаТЧ.Читатель; // Указываем конкретного читателя
        Движение.Количество = 1;

    КонецЦикла;

КонецПроцедуры

Важный момент: Мы видим, что в коде нет прямого обращения к справочнику Книги для изменения реквизита Статус. Все изменения состояния книги фиксируются в регистре накоплений.

Документ ВозвратКниги

Для завершения цикла учета нам потребуется создать документ ВозвратКниги. Его структура будет аналогична документу ВыдачаКниги, но движения в обработке проведения будут обратными:


Процедура ОбработкаПроведения(Отказ, РежимПроведения)

    Движения.НаличиеКниг.Записывать = Истина;
    Движения.НаличиеКниг.Очистить();

    Для Каждого СтрокаТЧ Из ВозвращаемыеКниги Цикл // Предполагаем табличную часть ВозвращаемыеКниги
        // Шаг 1: Проверяем, что книга находится на руках у данного читателя
        Запрос = Новый Запрос;
        Запрос.Текст = 
            "ВЫБРАТЬ ПЕРВЫЕ 1
            |    НаличиеКнигОстатки.Книга КАК Книга,
            |    НаличиеКнигОстатки.КоличествоОстаток КАК Количество
            |ИЗ
            |    РегистрНакоплений.НаличиеКниг.Остатки(
            |        &МоментВремени,
            |        Книга = &Книга
            |            И МестоНахождения = &МестоНахожденияУЧитателя
            |            И Читатель = &Читатель
            |    ) КАК НаличиеКнигОстатки";
        Запрос.УстановитьПараметр("МоментВремени", МоментВремени());
        Запрос.УстановитьПараметр("Книга", СтрокаТЧ.Книга);
        Запрос.УстановитьПараметр("МестоНахожденияУЧитателя", Перечисления.МестаХраненияКниг.НаРукахУЧитателя);
        Запрос.УстановитьПараметр("Читатель", СтрокаТЧ.Читатель); // Читатель из табличной части

        РезультатЗапроса = Запрос.Выполнить();
        Выборка = РезультатЗапроса.Выбрать();

        Если НЕ Выборка.Следующий() Тогда
            Отказ = Истина;
            Сообщить("Экземпляр книги " + СтрокаТЧ.Книга.ИнвентарныйНомер + " ('" + СтрокаТЧ.Книга.Наименование + "') не находится на руках у читателя " + СтрокаТЧ.Читатель.Наименование + "!");
            Продолжить;
        КонецЕсли;

        // Шаг 2: Формируем движения регистра
        // Движение Расход: книга выбывает от читателя
        Движение = Движения.НаличиеКниг.Добавить();
        Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
        Движение.Период = Дата;
        Движение.Книга = СтрокаТЧ.Книга;
        Движение.МестоНахождения = Перечисления.МестаХраненияКниг.НаРукахУЧитателя;
        Движение.Читатель = СтрокаТЧ.Читатель;
        Движение.Количество = 1;

        // Движение Приход: книга поступает в библиотеку
        Движение = Движения.НаличиеКниг.Добавить();
        Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
        Движение.Период = Дата;
        Движение.Книга = СтрокаТЧ.Книга;
        Движение.МестоНахождения = Перечисления.МестаХраненияКниг.Библиотека;
        Движение.Количество = 1;

    КонецЦикла;

КонецПроцедуры

Когда может пригодиться Регистр сведений?

Хотя Регистр накоплений лучше подходит для учета движения и остатков экземпляров, Регистр сведений может быть полезен для хранения дополнительных, периодически изменяемых характеристик книги, которые не являются остатками. Например, если бы нам нужно было отслеживать не просто "Выдана/Доступна", а более сложные состояния или свойства, не связанные с количественным учетом, например, "Ветхая", "Требует ремонта", "На реставрации".

Если бы первоначальная задача была строго о хранении только статуса ("Выдана" / "Доступна") без детализации по конкретным экземплярам и количеству, Регистр сведений мог бы быть использован. Мы могли бы создать периодический Регистр сведений СтатусыЭкземпляровКниг.

Пример структуры Регистр Сведений СтатусыЭкземпляровКниг (периодический)

В этом случае при проведении документа ВыдачаКниги мы бы делали движения по этому регистру сведений, записывая новый статус и читателя:


Процедура ОбработкаПроведения(Отказ, РежимПроведения)
    // ... (возможно, проверка на доступность книги через этот же регистр) ...

    Движения.СтатусыЭкземпляровКниг.Записывать = Истина;
    Движения.СтатусыЭкземпляровКниг.Очистить();

    Для Каждого СтрокаТЧ Из ВыдаваемыеКниги Цикл
        Движение = Движения.СтатусыЭкземпляровКниг.Добавить();
        Движение.Период = Дата; // Момент проведения документа
        Движение.Книга = СтрокаТЧ.Книга;
        Движение.Статус = Перечисления.СтатусыКниг.Выдана;
        Движение.Читатель = СтрокаТЧ.Читатель;
    КонецЦикла;

КонецПроцедуры

И при возврате книги, статус менялся бы на "Доступна", а читатель очищался.

Однако, как мы уже отметили, Регистр накоплений обеспечивает более полный учет движения и наличия, что обычно требуется для библиотечных систем.

Дополнительные аспекты учета

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

  1. Изношенность и реставрация:
    • Мы можем добавить в справочник Книги (или в отдельный Регистр сведений, если нужно хранить историю изменений состояния) реквизиты, такие как КоэффициентИзноса (число от 0 до 1) или ФизическоеСостояние (перечисление: "Отличное", "Хорошее", "Удовлетворительное", "Ветхое").
    • Для фиксации операций реставрации можно создать отдельный документ РеставрацияКниги. Этот документ будет выполнять следующие действия:
      1. В Регистре накоплений НаличиеКниг будет выполняться движение Расход из текущего места нахождения (например, "Библиотека") и Приход в новое местонахождение ("ВРемонте" или "НаРеставрации").
      2. Также этот документ может обновлять реквизиты КоэффициентИзноса или ФизическоеСостояние в справочнике Книги (если это единоразовая операция без истории) или делать запись в Регистр сведений СостояниеКниг (если нам нужна история изменений состояния).
    • Для списания ветхих книг также создается отдельный документ СписаниеКниг, который делает движение Расход из Регистра накоплений НаличиеКниг и может изменять статус в справочнике Книги (если такой реквизит всё же будет) на "Списана".
  2. Инвентарный номер:
    • Как мы уже установили, критически важно, чтобы каждый физический экземпляр книги имел уникальный идентификатор. Для этого в справочнике Книги мы создаем реквизит ИнвентарныйНомер (Тип: Строка или Число), и устанавливаем ему свойство "Индексировать" с "Уникальность" для быстрого поиска и гарантии уникальности.
    • При заполнении документов ВыдачаКниги или ВозвратКниги можно использовать поиск по инвентарному номеру.
  3. ISBN:
    • ISBN (International Standard Book Number) является международным идентификатором издания, а не конкретного экземпляра. Его можно добавить в справочник Книги как отдельный реквизит (Тип: Строка) для информационной цели, поиска по изданиям и интеграции с внешними системами. Однако ISBN не может заменить ИнвентарныйНомер для пообъектного учета внутри библиотеки.

Всегда помните, что каждый дополнительный аспект учета должен быть оправдан реальной потребностью бизнеса и окупать затраты на его ведение и поддержку. В большинстве случаев для базового библиотечного учета достаточно отслеживания движения экземпляров через Регистр накоплений.

Заключение

Мы выяснили, что прямое изменение реквизита справочника в обработке проведения документа является неверным и неэффективным подходом. Вместо этого, для учета выдачи и статуса книг в 1С следует использовать Регистры накоплений (для учета движения и остатков экземпляров) и, при необходимости, Регистры сведений (для хранения периодически изменяемых характеристик). Этот подход обеспечивает гибкость, возможность получения данных на любую дату, корректное ведение истории движения каждого экземпляра книги и соответствует лучшим практикам разработки в 1С. Реализуя систему таким образом, мы создаем надежную и масштабируемую основу для библиотечного учета.

← На главную