Как в форме списка Счетов на оплату вывести сумму платежного ордера и сравнить их?

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

В процессе разработки в среде 1С:Предприятие 8.3 часто возникает задача визуального сопоставления данных из разных документов. Типичный пример для конфигурации Бухгалтерия предприятия 3.0 (БП 3.0) — необходимость видеть в списке Счетов на оплату, на какую сумму по ним были введены Платежные ордера. Это позволяет пользователю сразу видеть недоплату или переплату, не заходя в каждый отдельный документ.

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

Почему прямой запрос в процедуре ПриСозданииНаСервере — это ошибка?

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

Проанализируем пример кода, который часто приводит к неудаче:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    // ОШИБОЧНЫЙ ПУТЬ:
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ СвязанныеДокументы.Ссылка.СуммаДокумента ИЗ КритерийОтбора.СвязанныеДокументы КАК СвязанныеДокументы";
    // Этот запрос выберет данные, но не свяжет их со списком на форме
КонецПроцедуры

Чтобы данные отображались корректно для каждой строки, нам нужно модифицировать сам источник данных списка.

Шаг 1. Модификация запроса динамического списка

Для реализации нашей задачи в БП 3.0 правильнее всего использовать расширение конфигурации. Мы должны перехватить запрос динамического списка Список и добавить в него левое соединение с данными об оплатах.

Важный нюанс: Один счет может быть оплачен несколькими платежными документами. Если мы просто соединим таблицу счетов с таблицей платежей, в списке появятся дублирующиеся строки на каждый платеж. Чтобы этого избежать, мы обязаны использовать вложенный запрос с группировкой по документу-основанию.

Рассмотрим пример правильного запроса для динамического списка:


ВЫБРАТЬ
    ОсновнаяТаблица.Ссылка КАК Ссылка,
    ОсновнаяТаблица.Дата КАК Дата,
    ОсновнаяТаблица.Номер КАК Номер,
    ОсновнаяТаблица.СуммаДокумента КАК СуммаДокумента,
    ЕСТЬNULL(ВТ_Оплаты.СуммаОплаты, 0) КАК СуммаОплаты
ИЗ
    Документ.СчетНаОплатуПокупателю КАК ОсновнаяТаблица
        ЛЕВОЕ СОЕДИНЕНИЕ (
            ВЫБРАТЬ
                СвязанныеДокументы.Кювета КАК ДокументОснование,
                СУММА(СвязанныеДокументы.Ссылка.СуммаДокумента) КАК СуммаОплаты
            ИЗ
                КритерийОтбора.СвязанныеДокументы КАК СвязанныеДокументы
            ГДЕ
                ТИПЗНАЧЕНИЯ(СвязанныеДокументы.Ссылка) = ТИП(Документ.ПлатежныйОрдерПоступлениеДенежных Средств)
            СГРУППИРОВАТЬ ПО
                СвязанныеДокументы.Кювета
        ) КАК ВТ_Оплаты
        ПО ОсновнаяТаблица.Ссылка = ВТ_Оплаты.ДокументОснование

В этом запросе мы создаем виртуальную таблицу ВТ_Оплаты, которая предварительно суммирует все платежи по каждому счету, и только потом «подклеиваем» ее к списку счетов. Поле ЕСТЬNULL гарантирует, что если оплат нет, мы получим 0, а не пустое значение.

Шаг 2. Программное изменение формы через расширение

Поскольку мы работаем в БП 3.0, крайне не рекомендуется изменять типовую форму напрямую. Используем процедуру-последователь ПриСозданииНаСервере в расширении. Выясним, как программно добавить новые колонки и изменить текст запроса.


&НаСервере
&После("ПриСозданииНаСервере")
Процедура ИТ_ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // 1. Получаем текущий текст запроса
    ТекстЗапроса = Список.ТекстЗапроса;
    
    // 2. Модифицируем его (добавляем соединение, описанное выше)
    // Здесь можно использовать строковые функции СтрЗаменить или собрать запрос заново
    НовыйТекстЗапроса = "ВЫБРАТЬ ... (наш запрос с соединением)";
    Список.ТекстЗапроса = НовыйТекстЗапроса;
    
    // 3. Добавляем новое поле в пользовательские настройки, если нужно
    // Или просто выводим поле на форму
    НовыйЭлемент = Элементы.Добавить("СуммаОплаты", Тип("ПолеФормы"), Элементы.Список);
    НовыйЭлемент.Вид = ВидПоляФормы.ПолеВвода;
    НовыйЭлемент.ПутьКДанным = "Список.СуммаОплаты";
    НовыйЭлемент.Заголовок = "Сумма оплаты (ордера)";
    
КонецПроцедуры

Шаг 3. Настройка условного оформления

Теперь, когда у нас в каждой строке списка есть и СуммаДокумента (счет), и СуммаОплаты (платежки), мы можем их сравнить и выделить цветом расхождения. Выясним, как это сделать программно, чтобы оформление работало автоматически.

Нам необходимо настроить Условное оформление динамического списка. Мы будем сравнивать два поля одной строки.


&НаСервере
Процедура НастроитьОформлениеСписка()
    
    ЭлементОформления = Список.УсловноеОформление.Элементы.Добавить();
    
    // Устанавливаем, что именно мы хотим изменить (например, цвет фона)
    ЭлементОформления.Оформление.УстановитьЗначениеПараметра("ЦветФона", WebЦвета.СветлоКрасный);
    
    // Условие: СуммаОплаты < СуммаДокумента (недоплата)
    ЭлементОтбора = ЭлементОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
    ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("СуммаОплаты");
    ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Меньше;
    ЭлементОтбора.ПравоеЗначение = Новый ПолеКомпоновкиДанных("СуммаДокумента");
    
    // Указываем, какие поля красить (или всю строку)
    ПолеОформления = ЭлементОформления.Поля.Элементы.Добавить();
    ПолеОформления.Поле = Новый ПолеКомпоновкиДанных("СуммаОплаты");
    
КонецПроцедуры

Важный момент: Обратите внимание, что в ПравоеЗначение мы передаем не конкретное число, а объект ПолеКомпоновкиДанных. Это критически важно для сравнения двух колонок между собой внутри одной строки динамического списка.

Шаг 4. Оптимизация производительности

Использование КритерийОтбора.СвязанныеДокументы в запросе динамического списка может замедлить работу формы, если в базе сотни тысяч документов. Проанализируем более профессиональный подход.

В типовых конфигурациях 1С (таких как БП 3.0) оплата счетов часто фиксируется в регистрах накопления или сведениях (например, регистр накопления ОплатаСчетов). Обращение к виртуальным таблицам остатков или оборотов регистров работает на порядок быстрее, чем поиск через критерии отбора по всей базе. Рассмотрим, как изменится вложенный запрос в этом случае:


// Вместо обращения к критерию отбора используем обороты регистра
ЛЕВОЕ СОЕДИНЕНИЕ (
    ВЫБРАТЬ
        ОплатаСчетовОбороты.СчетНаОплату КАК Счет,
        СУММА(ОплатаСчетовОбороты.СуммаОборот) КАК СуммаОплаты
    ИЗ
        РегистрНакопления.ОплатаСчетов.Обороты КАК ОплатаСчетовОбороты
    СГРУППИРОВАТЬ ПО
        ОплатаСчетовОбороты.СчетНаОплату
) КАК ВТ_Оплаты
ПО ОсновнаяТаблица.Ссылка = ВТ_Оплаты.Счет

Использование индексированных полей регистра позволит списку «летать» даже при огромных объемах данных.

Резюме и рекомендации

Разберем основные выводы нашего исследования:

  1. Не используйте циклы в процедурах типа ПриСозданииНаСервере для получения данных каждой строки. Это путь к низкой производительности и ошибкам.
  2. Модифицируйте Динамический список. Это единственный правильный способ вывода связанных данных в управляемых формах 1С 8.3.
  3. Следите за группировками. При соединении таблиц «один-ко-многим» (один счет — много платежей) всегда делайте предварительную группировку во вложенном запросе, чтобы избежать дублей в списке.
  4. Используйте Условное оформление списка, а не всей формы. Это позволяет сравнивать поля строк динамически и визуально выделять важную информацию для бухгалтера.
  5. Работайте через расширения. Сохраняйте типовую конфигурацию на поддержке, вынося все изменения в отдельный слой метаданных.

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

← На главную