Как получить остатки товара в чеке ККМ: пошаговое руководство по исправлению кода и оптимизации

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

При работе с интерфейсом кассира часто возникает задача отображения актуальных остатков товара непосредственно в табличной части «Чека ККМ». Это позволяет кассиру оперативно ориентироваться в наличии товара без перехода в форму подбора. Рассмотрим, как правильно реализовать этот механизм, разберем типичные ошибки и выясним, почему код может возвращать нулевые значения.

Анализ исходной проблемы и поиск причин «нулевого» остатка

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

  1. Несоответствие типа склада и регистра: Это самая частая техническая ошибка. В системе 1С остатки могут храниться в разных регистрах в зависимости от типа склада. Если склад в документе имеет тип «Оптовый», данные нужно брать из регистра ТоварыНаСкладах. Если склад — «Розница» или «НТТ», то используется регистр ТоварыВРознице. В исходном коде используется ТоварыВРознице, и если в документе выбран оптовый склад, запрос всегда будет возвращать пустой результат.
  2. Передача пустой таблицы в параметры запроса: Посмотрим на формирование параметра ТаблицаНоменклатуры. Если выгрузка происходит из табличной части, которая еще не заполнена в базе или не обновлена в экранной форме, запрос получит пустой массив данных для отбора.
  3. Ошибка в условии ГДЕ: Использование обращений через точку, например, ТоварыНаСкладахОстатки.Номенклатура.Услуга = ЛОЖЬ, может приводить к исключению строк из результата, если свойство «Услуга» не заполнено или объект имеет другой тип.

Эффективный алгоритм получения остатков

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

Рассмотрим пошагово реализацию в событии ПриПолученииДанных. Это событие идеально подходит для обычных форм, так как оно срабатывает один раз для всего набора строк, видимых на экране.

Шаг 1. Формирование запроса с учетом типа склада

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


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

Запрос.УстановитьПараметр("Период", ТекущаяДата());
Запрос.УстановитьПараметр("Склад", СкладШапки);
Запрос.УстановитьПараметр("МассивНоменклатуры", МассивСсылок);

Обратите внимание: мы используем параметры виртуальной таблицы для отбора. Это работает значительно быстрее, чем фильтрация через секцию ГДЕ после выполнения запроса.

Шаг 2. Оптимизация обработки данных в цикле

Чтобы быстро сопоставить результат запроса со строками на экране, воспользуемся советом опытных разработчиков: выгрузим результат запроса в ТаблицаЗначений и обязательно проиндексируем ее по ключевым полям: Номенклатура и ХарактеристикаНоменклатуры. Это превратит поиск в мгновенную операцию.

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


// Получаем результат запроса
ТаблицаОстатков = Запрос.Выполнить().Выгрузить();
// Индексируем для быстрого поиска через НайтиСтроки
ТаблицаОстатков.Индексы.Добавить("Номенклатура, Характеристика");

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

Важные нюансы работы с контекстом

При реализации вывода остатков следует помнить о следующих моментах:

Использование соответствий (Map) как альтернатива

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


// Заполнение соответствия
ОстаткиХеш = Новый Соответствие;
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
    // Создаем уникальный ключ, если есть характеристики
    Ключ = Строка(Выборка.Номенклатура.УникальныйИдентификатор()) + Выборка.Характеристика.УникальныйИдентификатор();
    ОстаткиХеш.Вставить(Ключ, Выборка.Остаток);
КонецЦикла;

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

Заключение

Мы выяснили, что вывод остатков в чеке ККМ требует внимательного отношения к типам складов и используемым регистрам. Основной залог успеха — использование события ПриПолученииДанных, индексация временных таблиц и корректная передача параметров в виртуальные таблицы запроса. Помните, что избыточные запросы в цикле ПриВыводеСтроки могут существенно замедлить работу кассира, поэтому всегда стремитесь к пакетной обработке данных.

← На главную