Как вывести долг контрагента в макет печатной формы в 1С:Управление торговлей 11

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

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

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

Разбор типичной ошибки: почему возникает «Переменная не определена (СуммаОстаток)»?

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


// ОШИБОЧНЫЙ КОД
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	РасчетыСКлиентамиОстатки.СуммаОстаток КАК СуммаОстаток
    |ИЗ
    |	РегистрНакопления.РасчетыСКлиентами.Остатки КАК РасчетыСКлиентамиОстатки";

РезультатЗапроса = Запрос.Выполнить();
Запрос.УстановитьПараметр("ДогКлиента", СуммаОстаток); // Ошибка: Переменная не определена (СуммаОстаток)

Выясним причину этой ошибки. Программа сообщает о неопределенной переменной по двум важным причинам:

  1. Путаница между параметрами запроса и параметрами макета. Метод Запрос.УстановитьПараметр() служит для передачи данных внутрь запроса (например, для отбора по контрагенту), а не для получения данных из него. Для вывода данных в печатную форму нам нужно заполнять параметры ОбластиМакета.
  2. Отсутствие обхода результатов запроса. Переменная СуммаОстаток существует только в тексте запроса как имя колонки будущей таблицы результатов. Чтобы обратиться к этому значению в коде 1С, необходимо выполнить запрос, получить его выборку и спозиционироваться на нужной строке.

Давайте посмотрим на пример правильной структуры кода для извлечения данных из запроса:


// Выполняем запрос
РезультатЗапроса = Запрос.Выполнить();

// Создаем выборку для обхода результатов
Выборка = РезультатЗапроса.Выбрать();

// Переходим к первой (и в данном случае единственной) строке результата
Если Выборка.Следующий() Тогда
    // Получаем область макета
    ОбластьМакета = Макет.ПолучитьОбласть("Заказчик");
    
    // Заполняем параметр макета полученным значением из выборки
    ОбластьМакета.Параметры.ДолгКлиента = Выборка.СуммаОстаток;
КонецЕсли;

Настройка правильного отбора по контрагенту

Если запустить запрос в первоначальном виде, мы столкнемся со второй проблемой: запрос вернет общую сумму остатка по абсолютно всем контрагентам в базе данных (а в случае отсутствия движений может вернуть пустой результат). Нам же требуется получить долг конкретного клиента, для которого распечатывается документ.

Для этого необходимо наложить отбор на виртуальную таблицу остатков регистра накопления. В «1С:Управлении торговлей 11» взаиморасчеты ведутся в разрезе партнеров и контрагентов через аналитику учета. В простейшем случае мы можем сделать отбор по контрагенту, связав его с данными печатаемого документа. При необходимости контролировать задолженность еще на этапе выбора контрагента в документах продажи пригодится расширение для вывода долга партнеров в формы списков и выбора.

Обычно в процедуру печати передается структура или строка таблицы значений ДанныеПечати, содержащая реквизиты текущего документа (включая ссылку на сам документ, контрагента, организацию и т.д.). Мы воспользуемся этим, чтобы передать контрагента в параметры нашего запроса.

Модернизируем наш запрос и добавим в него параметры:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	РасчетыСКлиентамиОстатки.СуммаОстаток КАК СуммаОстаток
    |ИЗ
    |	РегистрНакопления.РасчетыСКлиентами.Остатки(, АналитикаУчетаПоПартнерам.Контрагент = &Контрагент) КАК РасчетыСКлиентамиОстатки";

// Передаем контрагента из данных печатаемого документа в параметр запроса
Запрос.УстановитьПараметр("Контрагент", ДанныеПечати.Контрагент);

РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

ОбластьМакета = Макет.ПолучитьОбласть("Заказчик");

// Инициализируем параметр макета значением по умолчанию (на случай, если долга нет)
ОбластьМакета.Параметры.ДолгКлиента = 0;

Если Выборка.Следующий() Тогда
    // Заполняем реальным значением задолженности
    ОбластьМакета.Параметры.ДолгКлиента = Выборка.СуммаОстаток;
КонецЕсли;

// Выводим заполненную область в табличный документ
ТабличныйДокумент.Вывести(ОбластьМакета);

Решение проблемы мультивалютных долгов

На практике у одного и того же контрагента могут быть незакрытые взаиморасчеты в разных валютах (например, в рублях и долларах США). В этом случае виртуальная таблица остатков вернет не одну строку, а несколько — по каждой валюте отдельно.

Если мы оставим код без изменений и используем конструкцию Если Выборка.Следующий() Тогда, программа выведет долг только по первой попавшейся валюте, проигнорировав остальные. Нам нужно обойти все строки выборки в цикле и сформировать красивую итоговую строку для вывода в макет.

Проанализируем, как решить эту задачу с помощью обхода в цикле Пока Выборка.Следующий():


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	РасчетыСКлиентамиОстатки.СуммаОстаток КАК СуммаОстаток,
    |	РасчетыСКлиентамиОстатки.Валюта.Символ КАК СимволВалюты,
    |	РасчетыСКлиентамиОстатки.Валюта.Наименование КАК ВалютаНаименование
    |ИЗ
    |	РегистрНакопления.РасчетыСКлиентами.Остатки(, АналитикаУчетаПоПартнерам.Контрагент = &Контрагент) КАК РасчетыСКлиентамиОстатки";

Запрос.УстановитьПараметр("Contragent", ДанныеПечати.Контрагент);

РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

ОбластьМакета = Макет.ПолучитьОбласть("Заказчик");

СтрокаДолга = "";

// Обходим все валютные остатки контрагента
Пока Выборка.Следующий() Цикл
    
    // Определяем представление валюты (символ или краткое наименование)
    ПредставлениеВалюты = ?(ЗначениеЗаполнено(Выборка.СимволВалюты), Выборка.SимволВалюты, Выборка.ВалютаНаименование);
    
    // Форматируем сумму долга для красивого вывода (например, 150 000,00)
    ФорматированнаяСумма = Формат(Выборка.СуммаОстаток, "ЧДЦ=2; ЧГ=3");
    
    // Собираем общую строку задолженности
    ТекущийДолг = ФорматированнаяСумма + " " + ПредставлениеВалюты;
    СтрокаДолга = СтрокаДолга + ?(СтрокаДолга = "", "", ", ") + ТекущийДолг;
    
КонецЦикла;

// Если долгов не обнаружено, пишем "Нет долга" или оставляем пустым
Если ПустаяСтрока(СтрокаДолга) Тогда
    СтрокаДолга = "0.00 руб.";
КонецЕсли;

// Устанавливаем итоговый параметр в макет
ОбластьМакета.Параметры.ДолгКлиента = СтрокаДолга;
ТабличныйДокумент.Вывести(ОбластьМакета);

Методологические нюансы работы с взаиморасчетами в УТ 11

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

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


// Получаем ключ аналитики расчетов программным путем
ПараметрыАналитики = РегистрыНакопления.РасчетыСКлиентами.ПараметрыАналитикиУчетаПоПартнерам();
ПараметрыАналитики.Партнер      = ДанныеПечати.Партнер;
ПараметрыАналитики.Контрагент   = ДанныеПечати.Контрагент;
ПараметрыАналитики.Организация  = ДанныеПечати.Организация;

КлючАналитики = РегистрыСведений.АналитикаУчетаПоПартнерам.ЗначениеКлючаАналитики(ПараметрыАналитики);

// Теперь наш запрос будет работать максимально быстро, используя индексированное поле
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	РасчетыСКлиентамиОстатки.СуммаОстаток КАК СуммаОстаток,
    |	РасчетыСКлиентамиОстатки.Валюта.Символ КАК СимволВалюты
    |ИЗ
    |	РегистрНакопления.РасчетыСКлиентами.Остатки(, АналитикаУчетаПоПартнерам = &АналитикаУчетаПоПартнерам) КАК РасчетыСКлиентамиОстатки";

Запрос.УстановитьПараметр("АналитикаУчетаПоПартнерам", КлючАналитики);

Использование этого метода гарантирует моментальное формирование печатной формы даже в базах данных с миллионами записей в регистре взаиморасчетов.

← На главную