При работе в конфигурациях на обычных формах (таких как «1С:Управление торговым предприятием» или «1С:Управление торговлей 10.3») пользователи часто сталкиваются с тем, что стандартная обработка печати ценников по умолчанию предлагает напечатать ровно по одной копии для каждого товара. Поле Количество в запросе жестко заполнено единицей: 1 КАК Количество. На практике же торговым точкам необходимо печатать ровно столько ценников, сколько единиц товара сейчас реально находится на складе.
В этой статье мы подробно разберем, почему простая замена единицы на поле остатка в запросе приводит к ошибке «Поле не найдено НаСкладе.Количество», проанализируем логику динамического построения запросов в 1С и найдем правильные, отказоустойчивые варианты решения этой задачи.
Рассмотрим структуру кода, которую использует разработчик в попытке решить задачу. В процедуре обработки текст запроса собирается динамически из нескольких частей. Обратим внимание на ключевой фрагмент кода:
ТекстЗапроса = "
|ВЫБРАТЬ
| ИСТИНА КАК Печать,
| СпрНоменклатура.Номенклатура КАК Номенклатура,
| СпрНоменклатура.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
| СпрНоменклатура.Номенклатура.ЕдиницаХраненияОстатков КАК ЕдиницаИзмерения,
| 0 КАК Цена,
| НаСкладе.Количество КАК Количество
| (ВЫБРАТЬ ...
";
При попытке выполнить такой запрос платформа выдает ошибку о том, что поле не найдено. Проанализировав ситуацию, мы можем выделить сразу три грубые ошибки:
ИЗ, что делает запрос синтаксически некорректным.Если ТолькоИмеющиесяВНаличии Тогда ... КонецЕсли;. Секция ЛЕВОЕ СОЕДИНЕНИЕ с виртуальными таблицами остатков (ТоварыНаСкладах.Остатки, ТоварыВРознице.Остатки и т.д.) добавляется к тексту запроса только тогда, когда на форме взведен соответствующий флаг. Если этот флаг снят, то таблица НаСкладе вообще не попадает в итоговый текст запроса. СУБД делает выборку из справочника номенклатуры, видит в полях НаСкладе.Количество и выдает закономерную ошибку: поле не найдено, так как источник данных отсутствует.NULL. Без использования функции ЕСТЬNULL это приведет к ошибкам при выводе на печать или расчете количества копий.Рассмотрим два надежных способа исправления этого алгоритма.
Разберем по шагам первый вариант решения. Раз уж соединение с остатками подключается динамически, то и само поле Количество в секции ВЫБРАТЬ должно формироваться в зависимости от флага ТолькоИмеющиесяВНаличии. Если флаг установлен — мы выбираем остаток на складе. Если флаг снят — мы подставляем значение 1.
Для реализации этого подхода перепишем инициализацию запроса следующим образом:
// Определяем, какое поле будет отвечать за количество ценников
ПолеКоличество = ?(ТолькоИмеющиесяВНаличии, "ЕСТЬNULL(НаСкладе.Количество, 0)", "1");
ТекстЗапроса = "
|ВЫБРАТЬ
| ИСТИНА КАК Печать,
| СпрНоменклатура.Номенклатура КАК Номенклатура,
| СпрНоменклатура.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
| СпрНоменклатура.Номенклатура.ЕдиницаХраненияОстатков КАК ЕдиницаИзмерения,
| 0 КАК Цена,
| " + ПолеКоличество + " КАК Количество
|ИЗ
| (ВЫБРАТЬ
| СпрНоменклатура.Ссылка КАК Номенклатура,
| ЗНАЧЕНИЕ(Справочник.ХарактеристикиНоменклатуры.ПустаяСсылка) КАК ХарактеристикаНоменклатуры
| ИЗ
| Справочник.Номенклатура КАК СпрНоменклатура
| ГДЕ НЕ СпрНоменклатура.ЭтоГруппа
| {ГДЕ
| СпрНоменклатура.Ссылка.* КАК Номенклатура}
| ОБЪЕДИНИТЬ ВСЕ
| ВЫБРАТЬ
| СпрХарактеристики.Владелец,
| СпрХарактеристики.Ссылка
| ИЗ
| Справочник.ХарактеристикиНоменклатуры КАК СпрХарактеристики
| {ГДЕ
| СпрХарактеристики.Владелец.* КАК Номенклатура,
| СпрХарактеристики.Ссылка.* КАК ХарактеристикаНоменклатуры}
| ) КАК СпрНоменклатура
|";
Далее мы оставляем стандартное добавление левого соединения и упорядочивания. Этот метод хорош тем, что он минимально меняет исходную логику типовой обработки и гарантированно защищает от ошибок компиляции запроса при любом положении флага на форме.
Более изящным и правильным с точки зрения структуры запросов решением является постоянное (статическое) подключение таблицы остатков. Мы всегда соединяем номенклатуру с остатками на складах. Если товара нет на складе, поле количества вернет нам 0 или NULL, которые мы обработаем.
Флаг ТолькоИмеющиесяВНаличии в этом случае будет влиять исключительно на фильтрацию строк в секции ГДЕ. Проанализируем этот алгоритм и реализуем его в коде:
ТекстЗапроса = "
|ВЫБРАТЬ
| ИСТИНА КАК Печать,
| СпрНоменклатура.Номенклатура КАК Номенклатура,
| СпрНоменклатура.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
| СпрНоменклатура.Номенклатура.ЕдиницаХраненияОстатков КАК ЕдиницаИзмерения,
| 0 КАК Цена,
| ВЫБОР
| КОГДА ЕСТЬNULL(НаСкладе.Количество, 0) <= 0 ТОГДА 1
| ИНАЧЕ ВЫРАЗИТЬ(НаСкладе.Количество КАК ЧИСЛО(15, 0))
| КОНЕЦ КАК Количество
|ИЗ
| (ВЫБРАТЬ
| СпрНоменклатура.Ссылка КАК Номенклатура,
| ЗНАЧЕНИЕ(Справочник.ХарактеристикиНоменклатуры.ПустаяСсылка) КАК ХарактеристикаНоменклатуры
| ИЗ
| Справочник.Номенклатура КАК СпрНоменклатура
| ГДЕ НЕ СпрНоменклатура.ЭтоГруппа
| {ГДЕ
| СпрНоменклатура.Ссылка.* КАК Номенклатура}
| ОБЪЕДИНИТЬ ВСЕ
| ВЫБРАТЬ
| СпрХарактеристики.Владелец,
| СпрХарактеристики.Ссылка
| ИЗ
| Справочник.ХарактеристикиНоменклатуры КАК СпрХарактеристики
| {ГДЕ
| СпрХарактеристики.Владелец.* КАК Номенклатура,
| СпрХарактеристики.Ссылка.* КАК ХарактеристикаНоменклатуры}
| ) КАК СпрНоменклатура
|
|ЛЕВОЕ СОЕДИНЕНИЕ
| (ВЫБРАТЬ
| НаСкладе.Номенклатура,
| НаСкладе.ХарактеристикаНоменклатуры,
| СУММА(НаСкладе.Количество) КАК Количество
| ИЗ
| (ВЫБРАТЬ
| НаСкладе.Номенклатура,
| НаСкладе.ХарактеристикаНоменклатуры,
| НаСкладе.КоличествоОстаток КАК Количество
| ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(, {Номенклатура.* КАК Номенклатура,
| ХарактеристикаНоменклатуры.* КАК ХарактеристикаНоменклатуры,
| Склад.* КАК Склад}) КАК НаСкладе
| ОБЪЕДИНИТЬ ВСЕ
| ВЫБРАТЬ
| ВРознице.Номенклатура,
| ВРознице.ХарактеристикаНоменклатуры,
| ВРознице.КоличествоОстаток КАК Количество
| ИЗ
| РегистрНакопления.ТоварыВРознице.Остатки(, {Номенклатура.* КАК Номенклатура,
| ХарактеристикаНоменклатуры.* КАК ХарактеристикаНоменклатуры,
| Склад.* КАК Склад}) КАК ВРознице
| ОБЪЕДИНИТЬ ВСЕ
| ВЫБРАТЬ
| ВНТТ.Номенклатура,
| ВНТТ.ХарактеристикаНоменклатуры,
| ВНТТ.КоличествоОстаток КАК Количество
| ИЗ
| РегистрНакопления.ТоварыВНТТ.Остатки(, {Номенклатура.* КАК Номенклатура,
| ХарактеристикаНоменклатуры.* КАК ХарактеристикаНоменклатуры,
| Склад.* КАК Склад}) КАК ВНТТ
| ) КАК НаСкладе
| СГРУППИРОВАТЬ ПО
| НаСкладе.Номенклатура,
| НаСкладе.ХарактеристикаНоменклатуры
| ) КАК НаСкладе
|ПО
| СпрНоменклатура.Номенклатура = НаСкладе.Номенклатура
| И СпрНоменклатура.ХарактеристикаНоменклатуры = НаСкладе.ХарактеристикаНоменклатуры
|";
Если ТолькоИмеющиесяВНаличии Тогда
ТекстЗапроса = ТекстЗапроса + "
|ГДЕ
| ЕСТЬNULL(НаСкладе.Количество, 0) > 0
|";
КонецЕсли;
ТекстЗапроса = ТекстЗапроса + "
|УПОРЯДОЧИТЬ ПО
| СпрНоменклатура.Номенклатура.Наименование,
| СпрНоменклатура.ХарактеристикаНоменклатуры.Наименование
|";
В этом варианте мы применили конструкцию ВЫБОР КОГДА ... КОНЕЦ. Она позволяет элегантно обойти проблему отрицательных остатков (когда в системе разрешены отгрузки «в минус»). Если на складе числится количество меньше или равное нулю, система автоматически подставит 1 ценник для печати, чтобы вы могли промаркировать витринный образец. Если же товар есть в наличии, мы используем конструкцию ВЫРАЗИТЬ для приведения дробных остатков к целому числу копий ценников.
Когда мы дорабатываем печать ценников по фактическим остаткам, необходимо учитывать специфику ведения учета на предприятии:
Номенклатура, но и по полю ХарактеристикаНоменклатуры, как это реализовано в нашем запросе. Иначе остатки по разным цветам одной футболки просуммируются, и для каждого цвета распечатается избыточное количество ценников.1.540 кг бананов или 2.8 метра кабеля) при выводе на печать может вызвать ошибку принтера или платформы, так как нельзя распечатать полтора бумажных листа. Мы решили эту проблему в Способе 2 с помощью явного приведения типов СУБД: ВЫРАЗИТЬ(Количество КАК ЧИСЛО(15, 0)). Дробная часть будет корректно отсечена или округлена до целого числа копий.КОГДА ЕСТЬNULL(НаСкладе.Количество, 0) <= 0 ТОГДА 1. Если этого не сделать, отрицательное число в поле количества заблокирует печать или приведет к системной ошибке.Применив один из предложенных вариантов доработки, вы значительно упростите жизнь сотрудникам розничных магазинов и склада. Теперь им не придется вручную корректировать количество копий ценников в таблице перед отправкой на принтер этикеток.