Как проверить наличие определенной номенклатуры в табличной части документа для изменения печатной формы в 1С

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

При оформлении торговых операций часто возникает необходимость кастомизировать печатные формы под конкретные требования законодательства или особенности бизнес-процессов компании. Типичный пример — продажа лома и отходов черных или цветных металлов. Согласно Федеральному закону № 335-ФЗ, при реализации таких товаров продавец обязан выставлять первичные документы и счета-фактуры с пометкой «НДС исчисляется налоговым агентом».

В этой статье мы подробно разберем, как с помощью запроса быстро проверить, присутствует ли в табличной части документа «Реализация товаров и услуг» номенклатура из определенной группы (например, «Металлолом»), и на основе этого скорректировать вывод информации в печатных формах ТОРГ-12 и Счет-фактура. Мы проанализируем ошибки начинающих разработчиков, рассмотрим оптимальные методы написания запросов и научимся интегрировать проверку в механизмы БСП (Библиотеки Стандартных Подсистем) без нарушения стандартов разработки.

Штатные возможности 1С без доработки кода

Прежде чем переходить к программированию, важно отметить, что в типовых конфигурациях 1С (например, в 1С:Бухгалтерия 8 КОРП или 1С:ERP) данный функционал уже автоматизирован:

  1. В настройках функциональности программы достаточно включить признак «Организация – налоговый агент по НДС» и активировать обратное начисление налога.
  2. В договоре с покупателем необходимо установить флаг «Покупатель выступает в качестве налогового агента по уплате НДС».
  3. При выборе такого договора в документе реализации программа автоматически уберет стандартные ставки НДС и выведет надпись «НДС исчисляется налоговым агентом» во всех печатных формах (ТОРГ-12, УПД, Счета-фактуры).

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

Шаг 1. Анализируем исходную проблему и неоптимальный код

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


Металлалом = Справочники.Номенклатура.TargetGroup; // Получение группы
Металл = Ложь;
СФ = МассивОбъектов[0];
Если ТипЗнч(СФ) = Тип("ДокументСсылка.РеализацияТоваровУслуг") Тогда
    Для Каждого стрТЗ Из СФ.Товары Цикл
        Если стрТЗ.Номенклатура.ПринадлежитЭлементу(Металлалом) Тогда
            Металл = Истина;
        КонецЕсли;
    КонецЦикла;
КонецЕсли;

Почему этот подход считается плохим?

Шаг 2. Пишем эффективный запрос для проверки номенклатуры

Для быстрой проверки наличия хотя бы одной позиции из целевой группы (или конкретного элемента) в табличной части документа правильнее всего использовать запрос с конструкцией ВЫБРАТЬ ПЕРВЫЕ 1. Это позволит СУБД прекратить поиск сразу же после нахождения первого совпадения, минимизируя нагрузку.

Рассмотрим структуру оптимального запроса:


Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ ПЕРВЫЕ 1
|    ИСТИНА КАК ЕстьМеталл
|ИЗ
|    Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары
|ГДЕ
|    РеализацияТоваровУслугТовары.Ссылка = &Документ
|    И РеализацияТоваровУслугТовары.Номенклатура В ИЕРАРХИИ (&ГруппаНоменклатуры)";

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

РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
    // Номенклатура найдена, выполняем необходимые действия
КонецЕсли;

Разберем ключевые особенности этого запроса подробнее:

Шаг 3. Интеграция в модуль печати ТОРГ-12

В типовых конфигурациях печать ТОРГ-12 обычно выполняется через общий модуль (например, ПечатьТорговыхДокументов) в функции ПечатьТОРГ12. Нам необходимо передать ссылку на печатаемый документ в параметры нашего запроса.

Разберем пример интеграции в обработчик печати:


// Внутри функции ПечатьТОРГ12(СведенияТОРГ12, ОбъектыПечати, ПараметрыПечати)

// Получаем ссылку на текущий обрабатываемый документ из структуры СведенияТОРГ12
СсылкаНаДокумент = СведенияТОРГ12[0].Документ; 

// Рекомендуется избегать поиска по коду, но для наглядности используем этот метод
ГруппаМеталлолом = Справочники.Номенклатура.НайтиПоКоду("00009724");

ЗапросПроверки = Новый Запрос;
ЗапросПроверки.Текст = 
"ВЫБРАТЬ ПЕРВЫЕ 1
|    ИСТИНА КАК ЕстьМеталл
|ИЗ
|    Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары
|ГДЕ
|    РеализацияТоваровУслугТовары.Ссылка = &Документ
|    И РеализацияТоваровУслугТовары.Номенклатура В ИЕРАРХИИ (&Номенклатура)";

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

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

Шаг 4. Обработка групповой печати (Важно!)

В кодовой базе разработчика с форума присутствует серьезная архитектурная ошибка: использование индекса СведенияТОРГ12[0]. Если пользователь выделит в списке документов несколько реализаций и отправит их на печать одновременно, ваш алгоритм проверит на наличие металлолома только самый первый документ из списка, а для остальных выведет неверные данные.

Рассмотрим, как правильно реализовать пакетную проверку для массива документов:


// Собираем все документы из входящей структуры в массив
МассивДокументов = Новый Массив;
Для Каждого СведенияИзДокумента Из СведенияТОРГ12 Цикл
    МассивДокументов.Добавить(СведенияИзДокумента.Документ);
КонецЦикла;

ЗапросПакетный = Новый Запрос;
ЗапросПакетный.Текст = 
"ВЫБРАТЬ РАЗЛИЧНЫЕ
|    РеализацияТоваровУслугТовары.Ссылка КАК Документ
|ИЗ
|    Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары
|ГДЕ
|    РеализацияТоваровУслугТовары.Ссылка В (&МассивДокументов)
|    И РеализацияТоваровУслугТовары.Номенклатура В ИЕРАРХИИ (&Номенклатура)";

ЗапросПакетный.УстановитьПараметр("МассивДокументов", МассивДокументов);
ЗапросПакетный.УстановитьПараметр("Номенклатура", ГруппаМеталлолом);

// Выгружаем список документов, в которых действительно есть металлолом
ТаблицаДокументовСМеталлом = ЗапросПакетный.Выполнить().Выгрузить();

// Теперь при обходе печатных форм мы можем быстро сверяться с полученной таблицей
Для Каждого СтрокаСведений Из СведенияТОРГ12 Цикл
    ДокументСодержитМеталл = (ТаблицаДокументовСМеталлом.Найти(СтрокаСведений.Документ, "Документ") <> Неопределено);
    
    Если ДокументСодержитМеталл Тогда
        // Применяем настройки для налогового агента
    КонецЕсли;
КонецЦикла;

Шаг 5. Реализация проверки для печатной формы Счет-фактура

Счет-фактура выставляется на основании документа реализации. Чтобы выполнить проверку для печатной формы Счет-фактура, нам сначала необходимо получить документ-основание. Проанализируем, как это сделать с помощью запроса:


// Предположим, что СФ - это ссылка на СчетФактураВыданный
СсылкаНаСФ = МассивОбъектов[0];

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

ЗапросСФ.УстановитьПараметр("СсылкаНаСФ", СсылкаНаСФ);
ЗапросСФ.УстановитьПараметр("Номенклатура", ГруппаМеталлолом);

Металл = Не ЗапросСФ.Perform().IsEmpty(); // Проверяем результат выполнения

Если Металл Тогда
    // Заполняем область макета Счета-фактуры требуемым текстом
    ОбластьМакета.Параметры.СтавкаНДС = "НДС исчисляется налоговым агентом";
КонецЕсли;

Использование ВНУТРЕННЕЕ СОЕДИНЕНИЕ позволяет за один проход СУБД связать таблицу оснований счета-фактуры с табличной частью документа реализации и мгновенно проверить номенклатуру без распаковки объектов в памяти 1С.

Правила хорошего тона (Best Practices) при написании таких проверок

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

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

← На главную