Как реализовать отображение и хранение остатков в справочнике Номенклатура через подписки на события

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

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

Постановка задачи и выбор метода

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

Существует три основных пути решения этой задачи:

  1. Создание реквизита в справочнике, который обновляется подпиской на события при проведении документов.
  2. Использование динамического списка с произвольным запросом к виртуальным таблицам остатков (стандартный подход 1С).
  3. Использование вспомогательного регистра сведений для хранения «плоских» данных для обмена.

Реализация через подписки на события (обновление реквизита)

Рассмотрим по шагам, как реализовать логику, при которой каждый документ, влияющий на остатки, будет обновлять значение в справочнике Номенклатура. Нам понадобятся две подписки на события для всех документов, делающих движения по регистру ТоварыНаСкладах (или аналогичному): ОбработкаПроведения и ОбработкаУдаленияПроведения.

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


Процедура ПриПроведенииДокументаОбновитьОстатки(Источник, Отказ, РежимПроведения) Экспорт
    // Получаем уникальный массив номенклатуры из движений документа
    ТаблицаДвижений = Источник.Движения.ТоварыНаСкладах.Выгрузить();
    СписокНоменклатуры = ТаблицаДвижений.ВыгрузитьКолонку("Номенклатура");
    
    // Удаляем дубли, чтобы не записывать один объект дважды
    МассивОбъектов = Новый Массив;
    Для Каждого СсылкаНоменклатуры Из СписокНоменклатуры Цикл
        Если МассивОбъектов.Найти(СсылкаНоменклатуры) = Неопределено Тогда
            МассивОбъектов.Добавить(СсылкаНоменклатуры);
        КонецЕсли;
    КонецЦикла;

    // Обновляем остатки в реквизите справочника
    Для Каждого Ссылка Из МассивОбъектов Цикл
        ОбъектНоменклатура = Ссылка.ПолучитьОбъект();
        // Запрос к регистру для получения актуального остатка по всем складам
        ОбъектНоменклатура.ОстатокНаСкладе = РегистрыНакопления.ТоварыНаСкладах.Остатки( , Новый Структура("Номенклатура", Ссылка))[0].ВНаличииОстаток;
        ОбъектНоменклатура.Записать();
    КонецЦикла;
КонецПроцедуры

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

Альтернатива: Динамический список с вычисляемой колонкой

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

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

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

Этот метод не нагружает базу данных при проведении документов и всегда показывает актуальные цифры пользователю.

Решение для обмена с сайтом: Очередь изменений

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

Проанализируем преимущества этого метода:

Сложные случаи: Учет складов и характеристик

Если в системе ведется учет в разрезе складов или характеристик, хранение остатка в одном реквизите справочника становится практически невозможным. Рассмотрим почему:

Для сайта может потребоваться остаток конкретной модели (размер/цвет) на конкретном магазине. В этом случае в подписке на событие нужно реализовать логику агрегации данных. Посмотрим на пример структуры вспомогательного регистра сведений АктуальныеОстаткиДляСайта:

В подписке на события мы будем обновлять записи именно в этом регистре. Это позволит сайту делать быстрый запрос к плоской таблице без необходимости рассчитывать итоги по сложным регистрам накопления 1С.

Резюме и рекомендации

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

← На главную