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