Как правильно реализовать перемещение товаров между категориями: регистр сведений или регистр накопления?

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

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

В чем заключается архитектурная проблема

Рассмотрим типовую постановку задачи: в системе есть товар, его количество и категория («Ликвидный» / «Неликвидный»). Пользователь с помощью обработки выбирает товар и хочет перевести определенное количество из одной категории в другую. Допустим, мы пробуем решить это через независимый регистр сведений, просто перезаписывая строку с количеством и удаляя записи с нулевым остатком. Выясним причину, почему это решение является ошибочным с точки зрения архитектуры «1С:Предприятия».

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

Вариант 1. Использование регистра накопления и служебного документа

Проанализируем классический подход платформы. Для количественного учета остатков в разрезе категорий мы создаем регистр накопления остатков (например, ТоварыПоКатегориям) со следующей структурой:

  1. Измерения: Номенклатура (СправочникСсылка.Номенклатура), Категория (ПеречислениеСсылка.КатегорииЛиквидности).
  2. Ресурсы: Количество (Число).

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

Разберем по шагам, как выглядит программное формирование движений перемещения из обработки:


&НаСервере
Процедура ПереместитьТоварМеждуКатегориями(Товар, Количество, КатегорияОтправитель, КатегорияПолучатель)

    Блокировка = Новый БлокировкаДанных;
    ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.ТоварыПоКатегориям");
    ЭлементБлокировки.УстановитьЗначение("Номенклатура", Товар);
    ЭлементБлокировки.УстановитьЗначение("Категория", КатегорияОтправитель);

    НачатьТранзакцию();
    Попытка
        Блокировка.Заблокировать();

        // Проверяем актуальный остаток перед списанием
        Запрос = Новый Запрос;
        Запрос.Текст = 
            "ВЫБРАТЬ
            |   Остатки.КоличествоОстаток КАК Остаток
            |ИЗ
            |   РегистрНакопления.ТоварыПоКатегориям.Остатки(, Номенклатура = &Номенклатура И Категория = &Категория) КАК Остатки";
        Запрос.УстановитьПараметр("Номенклатура", Товар);
        Запрос.УстановитьПараметр("Категория", КатегорияОтправитель);

        Выборка = Запрос.Выполнить().Выбрать();
        ТекущийОстаток = 0;
        Если Выборка.Следующий() Тогда
            ТекущийОстаток = Выборка.Остаток;
        КонецЕсли;

        Если ТекущийОстаток < Количество Тогда
            ВызватьИсключение "Недостаточно товара в исходной категории для перемещения!";
        КонецЕсли;

        // Создаем служебный документ-регистратор
        ДокПеремещение = Документы.ПеремещениеТоваровПоКатегориям.СоздатьДокумент();
        ДокПеремещение.Дата = ТекущаяДатаСеанса();
        ДокПеремещение.Комментарий = "Сформировано автоматически из рабочей обработки";
        ДокПеремещение.Записать(РежимЗаписиДокумента.Запись);

        // Формируем движения: расход из старой категории, приход в новую
        НаборДвижений = ДокПеремещение.Движения.ТоварыПоКатегориям;

        ДвижениеРасход = НаборДвижений.ДобавитьРасход();
        ДвижениеРасход.Период = ДокПеремещение.Дата;
        ДвижениеРасход.Номенклатура = Товар;
        ДвижениеРасход.Категория = КатегорияОтправитель;
        ДвижениеРасход.Количество = Количество;

        ДвижениеПриход = НаборДвижений.ДобавитьПриход();
        ДвижениеПриход.Период = ДокПеремещение.Дата;
        ДвижениеПриход.Номенклатура = Товар;
        ДвижениеПриход.Категория = КатегорияПолучатель;
        ДвижениеПриход.Количество = Количество;

        НаборДвижений.Записать();
        ДокПеремещение.Записать(РежимЗаписиДокумента.Проведение);

        ЗафиксироватьТранзакцию();
    Исключение
        ОтменитьТранзакцию();
        ВызватьИсключение;
    КонецПопытки;

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

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

Вариант 2. Использование универсального документа корректировки

Если бизнес-требования запрещают добавлять в конфигурацию новый отдельный вид документа ради одной операции, рассмотрим использование типовых механизмов. В большинстве конфигураций 1С присутствует универсальный документ КорректировкаРегистров (или ОперацияБух в бухгалтерских конфигурациях).

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

Вариант 3. Типовые архитектурные альтернативы без кастомных регистров

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

  1. Виртуальные склады и места хранения. Создается склад или помещение «Склад неликвидного товара» (или «Зона брака»). Перевод товара между категориями оформляется типовым документом ПеремещениеТоваров. Это автоматически решает вопросы материальной ответственности, логистики, резервирования и оценки себестоимости.
  2. Учет по характеристикам или сериям. Если категория ликвидности привязана к физическим свойствам конкретной партии, признак ликвидности выносится в характеристику номенклатуры или в статус серии. В этом случае количественный и суммовой учет работает в рамках уже существующих типовых регистров остатков.
  3. Встроенный механизм градации качества. В ряде комплексных решений (например, 1C:ERP, Комплексная автоматизация, Управление торговлей) предусмотрен штатный механизм связей номенклатуры разного качества. Перевод кондиционного товара в брак или неликвид выполняется специализированными документами, такими как ПорчаТоваров или ПересортицаТоваров.

Таким образом, для количественных остатков всегда следует отдавать предпочтение регистру накопления и документу-регистратору (либо типовым механизмам учета), а регистры сведений оставлять исключительно для хранения нормативно-справочной информации, срезов цен и статических свойств объектов.

← На главную