При разработке печатных форм в 1С:УТП (или других конфигурациях на обычных формах) программисты часто сталкиваются с ситуацией, когда данные из регистра сведений «подтягиваются» некорректно. Одной из самых коварных ошибок является «залипание» значений: если для текущей строки товара штрихкод не найден, программа выводит штрихкод от предыдущего товара. В этой статье мы подробно разберем, почему это происходит и как правильно организовать выборку данных из регистра Штрихкоды.
Разберем ситуацию: мы перебираем строки документа (например, Реализации товаров и услуг) и для каждой строки пытаемся найти штрихкод определенного типа (например, EAN8). Если мы используем один и тот же объект области макета, то 1С сохраняет значения его параметров до тех пор, пока они не будут явно перезаписаны.
Проанализируем типичную ошибку в коде:
Характеристика = ВыборкаСтрокТовары.Характеристика;
ТипEAN8 = ПланыВидовХарактеристик.ТипыШтрихкодов.EAN8;
НаборЗаписей = РегистрыСведений.Штрихкоды.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.ХарактеристикаНоменклатуры.Установить(Характеристика);
НаборЗаписей.Отбор.ТипШтрихКода.Установить(ТипEAN8);
НаборЗаписей.Прочитать();
Для Каждого Запись Из НаборЗаписей Цикл
ОбластьМакета.Параметры.ШтрихКод = Запись.ШтрихКод;
КонецЦикла;
Если для следующего товара в выборке НаборЗаписей окажется пустым (т.е. штрихкод EAN8 не задан), цикл Для Каждого просто не выполнится. Следовательно, значение ОбластьМакета.Параметры.ШтрихКод останется таким же, каким оно было на предыдущей итерации. Именно поэтому в печатной форме мы видим штрихкод «соседа».
Самый простой и быстрый способ исправить проблему — добавить блок Иначе или проверку количества записей в наборе. Нам нужно гарантировать, что если данных нет, параметр будет очищен. Рассмотрим исправленный вариант кода:
// ... код установки отборов ...
НаборЗаписей.Прочитать();
Если НаборЗаписей.Количество() > 0 Тогда
Для Каждого Запись Из НаборЗаписей Цикл
ОбластьМакета.Параметры.ШтрихКод = Запись.ШтрихКод;
ОбластьМакета.Параметры.КодУпаковки = Запись.КодУпаковки;
КонецЦикла;
Иначе
// Важный момент: очищаем параметры, если штрихкод не найден
ОбластьМакета.Параметры.ШтрихКод = "";
ОбластьМакета.Параметры.КодУпаковки = "";
КонецЕсли;
ТабДок.Вывести(ОбластьМакета);
Важный нюанс: Обратите внимание, что метод ТабДок.Вывести(ОбластьМакета) должен находиться вне цикла перебора записей штрихкодов, если вы уверены, что штрихкод уникален. Если же вы поместите вывод внутрь цикла, то при наличии нескольких штрихкодов у одного товара строка в документе «размножится» столько раз, сколько штрихкодов найдено.
Более надежный способ избежать проблем с «памятью» параметров — получать область макета заново на каждой итерации цикла обхода товаров. Когда мы вызываем метод ПолучитьОбласть(), система создает новый «чистый» объект области с пустыми параметрами.
Посмотрим на пример правильной структуры цикла:
Для Каждого СтрокаТовара Из Товары Цикл
// Каждый раз берем новую область - параметры гарантированно пустые
ОбластьСтрока = Макет.ПолучитьОбласть("Строка");
// Заполняем основные данные
ЗаполнитьЗначенияСвойств(ОбластьСтрока.Параметры, СтрокаТовара);
// Ищем штрихкод
Набор = РегистрыСведений.Штрихкоды.СоздатьНаборЗаписей();
Набор.Отбор.Владелец.Установить(СтрокаТовара.Номенклатура);
Набор.Отбор.ТипШтрихКода.Установить(ТипEAN8);
Набор.Прочитать();
Если Набор.Количество() > 0 Тогда
ОбластьСтрока.Параметры.ШтрихКод = Набор[0].ШтрихКод;
КонецЕсли;
ТабДок.Вывести(ОбластьСтрока);
КонецЦикла;
Использование СоздатьНаборЗаписей() или Выбрать() внутри цикла — это серьезная нагрузка на базу данных. Если в документе 100 строк, система выполнит 100 отдельных запросов к таблице штрихкодов. Рассмотрим, как сделать это правильно с помощью одного запроса.
Пример запроса, который сразу вернет товары со штрихкодами нужного типа:
ВЫБРАТЬ
ДокТовары.Номенклатура,
ДокТовары.ХарактеристикаНоменклатуры,
Штрихкоды.Штрихкод КАК ШтрихкодEAN8
ИЗ
Документ.РеализацияТоваровУслуг.Товары КАК ДокТовары
ЛЕВОЕ СОЕДИНЕНИЕ
РегистрСведений.Штрихкоды КАК Штрихкоды
ПО ДокТовары.Номенклатура = Штрихкоды.Владелец
И ДокТовары.ХарактеристикаНоменклатуры = Штрихкоды.ХарактеристикаНоменклатуры
И (Штрихкоды.ТипШтрихкода = &ТипEAN8)
ГДЕ
ДокТовары.Ссылка = &СсылкаНаДокумент
Проанализируем преимущества этого метода: мы используем ЛЕВОЕ СОЕДИНЕНИЕ. Если штрихкода в базе нет, поле ШтрихкодEAN8 примет значение NULL. При выводе в параметры макета NULL автоматически преобразуется в пустую строку (или пустое поле), что полностью решает проблему «залипания» без лишних проверок Если ... Тогда.
Работая с типовыми конфигурациями (УТП, УПП, УТ 10.3), важно помнить о структуре измерений регистра Штрихкоды. Ошибка автора темы часто заключается в недостаточном отборе. Выясним, на что нужно обратить внимание:
Номенклатура). Если характеристика называется «Красный», она может быть у сотни разных товаров. Отбор только по характеристике выберет штрихкоды всех товаров с цветом «Красный».ПлануВидовХарактеристик.ТипыШтрихкодов, так как в одной таблице хранятся и EAN13, и EAN8, и Code128.Чтобы ваша печатная форма работала корректно, следуйте этим правилам: во-первых, всегда очищайте параметры области, если данные не найдены; во-вторых, старайтесь получать область макета внутри цикла; в-третьих, по возможности откажитесь от запросов в цикле в пользу одного общего запроса ко всем данным документа. Это не только избавит вас от ошибок вывода, но и значительно ускорит работу программы.