Как настроить печать ценников по фактическому остатку на складе в 1С:УТП?

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

При работе в конфигурациях на обычных формах (таких как «1С:Управление торговым предприятием» или «1С:Управление торговлей 10.3») пользователи часто сталкиваются с тем, что стандартная обработка печати ценников по умолчанию предлагает напечатать ровно по одной копии для каждого товара. Поле Количество в запросе жестко заполнено единицей: 1 КАК Количество. На практике же торговым точкам необходимо печатать ровно столько ценников, сколько единиц товара сейчас реально находится на складе.

В этой статье мы подробно разберем, почему простая замена единицы на поле остатка в запросе приводит к ошибке «Поле не найдено НаСкладе.Количество», проанализируем логику динамического построения запросов в 1С и найдем правильные, отказоустойчивые варианты решения этой задачи.

Выясняем причину ошибки: почему ломается типовой запрос

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


ТекстЗапроса = "
|ВЫБРАТЬ
|    ИСТИНА КАК Печать,
|    СпрНоменклатура.Номенклатура КАК Номенклатура,
|    СпрНоменклатура.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
|    СпрНоменклатура.Номенклатура.ЕдиницаХраненияОстатков КАК ЕдиницаИзмерения,
|    0 КАК Цена,
|    НаСкладе.Количество КАК Количество
|    (ВЫБРАТЬ ...
";

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

  1. Пропущено ключевое слово ИЗ. В первой части строки инициализации запроса после описания полей выборки сразу идет открывающая скобка подзапроса. Пропущен оператор ИЗ, что делает запрос синтаксически некорректным.
  2. Нарушение логики динамического соединения. Обратите внимание на условие Если ТолькоИмеющиесяВНаличии Тогда ... КонецЕсли;. Секция ЛЕВОЕ СОЕДИНЕНИЕ с виртуальными таблицами остатков (ТоварыНаСкладах.Остатки, ТоварыВРознице.Остатки и т.д.) добавляется к тексту запроса только тогда, когда на форме взведен соответствующий флаг. Если этот флаг снят, то таблица НаСкладе вообще не попадает в итоговый текст запроса. СУБД делает выборку из справочника номенклатуры, видит в полях НаСкладе.Количество и выдает закономерную ошибку: поле не найдено, так как источник данных отсутствует.
  3. Отсутствие обработки значений NULL. При левом соединении для тех позиций номенклатуры, которых нет на складе, СУБД вернет значение NULL. Без использования функции ЕСТЬNULL это приведет к ошибкам при выводе на печать или расчете количества копий.

Рассмотрим два надежных способа исправления этого алгоритма.


Способ 1. Динамическое формирование поля «Количество» в коде

Разберем по шагам первый вариант решения. Раз уж соединение с остатками подключается динамически, то и само поле Количество в секции ВЫБРАТЬ должно формироваться в зависимости от флага ТолькоИмеющиесяВНаличии. Если флаг установлен — мы выбираем остаток на складе. Если флаг снят — мы подставляем значение 1.

Для реализации этого подхода перепишем инициализацию запроса следующим образом:


// Определяем, какое поле будет отвечать за количество ценников
ПолеКоличество = ?(ТолькоИмеющиесяВНаличии, "ЕСТЬNULL(НаСкладе.Количество, 0)", "1");

ТекстЗапроса = "
|ВЫБРАТЬ
|    ИСТИНА КАК Печать,
|    СпрНоменклатура.Номенклатура КАК Номенклатура,
|    СпрНоменклатура.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
|    СпрНоменклатура.Номенклатура.ЕдиницаХраненияОстатков КАК ЕдиницаИзмерения,
|    0 КАК Цена,
|    " + ПолеКоличество + " КАК Количество
|ИЗ
|    (ВЫБРАТЬ
|        СпрНоменклатура.Ссылка КАК Номенклатура,
|        ЗНАЧЕНИЕ(Справочник.ХарактеристикиНоменклатуры.ПустаяСсылка) КАК ХарактеристикаНоменклатуры
|    ИЗ
|        Справочник.Номенклатура КАК СпрНоменклатура
|    ГДЕ НЕ СпрНоменклатура.ЭтоГруппа
|    {ГДЕ
|        СпрНоменклатура.Ссылка.* КАК Номенклатура}
|    ОБЪЕДИНИТЬ ВСЕ
|    ВЫБРАТЬ
|        СпрХарактеристики.Владелец,
|        СпрХарактеристики.Ссылка
|    ИЗ
|        Справочник.ХарактеристикиНоменклатуры КАК СпрХарактеристики
|    {ГДЕ
|        СпрХарактеристики.Владелец.* КАК Номенклатура,
|        СпрХарактеристики.Ссылка.* КАК ХарактеристикаНоменклатуры}
|    ) КАК СпрНоменклатура
|";

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


Способ 2. Статическое левое соединение с остатками (рекомендуемый вариант)

Более изящным и правильным с точки зрения структуры запросов решением является постоянное (статическое) подключение таблицы остатков. Мы всегда соединяем номенклатуру с остатками на складах. Если товара нет на складе, поле количества вернет нам 0 или NULL, которые мы обработаем.

Флаг ТолькоИмеющиесяВНаличии в этом случае будет влиять исключительно на фильтрацию строк в секции ГДЕ. Проанализируем этот алгоритм и реализуем его в коде:


ТекстЗапроса = "
|ВЫБРАТЬ
|    ИСТИНА КАК Печать,
|    СпрНоменклатура.Номенклатура КАК Номенклатура,
|    СпрНоменклатура.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
|    СпрНоменклатура.Номенклатура.ЕдиницаХраненияОстатков КАК ЕдиницаИзмерения,
|    0 КАК Цена,
|    ВЫБОР 
|        КОГДА ЕСТЬNULL(НаСкладе.Количество, 0) <= 0 ТОГДА 1 
|        ИНАЧЕ ВЫРАЗИТЬ(НаСкладе.Количество КАК ЧИСЛО(15, 0)) 
|    КОНЕЦ КАК Количество
|ИЗ
|    (ВЫБРАТЬ
|        СпрНоменклатура.Ссылка КАК Номенклатура,
|        ЗНАЧЕНИЕ(Справочник.ХарактеристикиНоменклатуры.ПустаяСсылка) КАК ХарактеристикаНоменклатуры
|    ИЗ
|        Справочник.Номенклатура КАК СпрНоменклатура
|    ГДЕ НЕ СпрНоменклатура.ЭтоГруппа
|    {ГДЕ
|        СпрНоменклатура.Ссылка.* КАК Номенклатура}
|    ОБЪЕДИНИТЬ ВСЕ
|    ВЫБРАТЬ
|        СпрХарактеристики.Владелец,
|        СпрХарактеристики.Ссылка
|    ИЗ
|        Справочник.ХарактеристикиНоменклатуры КАК СпрХарактеристики
|    {ГДЕ
|        СпрХарактеристики.Владелец.* КАК Номенклатура,
|        СпрХарактеристики.Ссылка.* КАК ХарактеристикаНоменклатуры}
|    ) КАК СпрНоменклатура
|
|ЛЕВОЕ СОЕДИНЕНИЕ
|    (ВЫБРАТЬ
|        НаСкладе.Номенклатура,
|        НаСкладе.ХарактеристикаНоменклатуры,
|        СУММА(НаСкладе.Количество) КАК Количество
|    ИЗ
|        (ВЫБРАТЬ
|            НаСкладе.Номенклатура,
|            НаСкладе.ХарактеристикаНоменклатуры,
|            НаСкладе.КоличествоОстаток КАК Количество
|        ИЗ
|            РегистрНакопления.ТоварыНаСкладах.Остатки(, {Номенклатура.* КАК Номенклатура,
|               ХарактеристикаНоменклатуры.* КАК ХарактеристикаНоменклатуры,
|               Склад.* КАК Склад}) КАК НаСкладе
|        ОБЪЕДИНИТЬ ВСЕ
|        ВЫБРАТЬ
|            ВРознице.Номенклатура,
|            ВРознице.ХарактеристикаНоменклатуры,
|            ВРознице.КоличествоОстаток КАК Количество
|        ИЗ
|            РегистрНакопления.ТоварыВРознице.Остатки(, {Номенклатура.* КАК Номенклатура,
|               ХарактеристикаНоменклатуры.* КАК ХарактеристикаНоменклатуры,
|               Склад.* КАК Склад}) КАК ВРознице
|        ОБЪЕДИНИТЬ ВСЕ
|        ВЫБРАТЬ
|            ВНТТ.Номенклатура,
|            ВНТТ.ХарактеристикаНоменклатуры,
|            ВНТТ.КоличествоОстаток КАК Количество
|        ИЗ
|            РегистрНакопления.ТоварыВНТТ.Остатки(, {Номенклатура.* КАК Номенклатура,
|               ХарактеристикаНоменклатуры.* КАК ХарактеристикаНоменклатуры,
|               Склад.* КАК Склад}) КАК ВНТТ
|        ) КАК НаСкладе
|    СГРУППИРОВАТЬ ПО
|        НаСкладе.Номенклатура,
|        НаСкладе.ХарактеристикаНоменклатуры
|    ) КАК НаСкладе
|ПО
|    СпрНоменклатура.Номенклатура = НаСкладе.Номенклатура
|    И СпрНоменклатура.ХарактеристикаНоменклатуры = НаСкладе.ХарактеристикаНоменклатуры
|";

Если ТолькоИмеющиесяВНаличии Тогда
    ТекстЗапроса = ТекстЗапроса + "
    |ГДЕ
    |    ЕСТЬNULL(НаСкладе.Количество, 0) > 0
    |";
КонецЕсли;

ТекстЗапроса = ТекстЗапроса + "
|УПОРЯДОЧИТЬ ПО
|    СпрНоменклатура.Номенклатура.Наименование,
|    СпрНоменклатура.ХарактеристикаНоменклатуры.Наименование
|";

В этом варианте мы применили конструкцию ВЫБОР КОГДА ... КОНЕЦ. Она позволяет элегантно обойти проблему отрицательных остатков (когда в системе разрешены отгрузки «в минус»). Если на складе числится количество меньше или равное нулю, система автоматически подставит 1 ценник для печати, чтобы вы могли промаркировать витринный образец. Если же товар есть в наличии, мы используем конструкцию ВЫРАЗИТЬ для приведения дробных остатков к целому числу копий ценников.


Важные нюансы работы с остатками при печати ценников

Когда мы дорабатываем печать ценников по фактическим остаткам, необходимо учитывать специфику ведения учета на предприятии:

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

← На главную