Как вывести задолженность в форме списка справочника при выборе строки в 1С 8.3?

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

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

Типичные ошибки при реализации вывода остатков

При попытке рассчитать и показать остатки в событии таблицы формы начинающие разработчики часто сталкиваются со следующими проблемами:

  1. Обращение к элементам формы на сервере: Свойство ТекущиеДанные таблицы формы доступно исключительно в контексте &НаКлиенте. Попытка прочитать Элементы.Список.ТекущиеДанные внутри серверной процедуры приводит к ошибке выполнения или возврату невалидных данных.
  2. Обращение к объектам метаданных на клиенте: Менеджер Константы недоступен на клиенте. Любые обращения к константам, объектным данным или регистрам должны выполняться строго на сервере.
  3. Неэффективные условия в виртуальных таблицах: Попытка получить данные регистра через обращение к реквизитам регистратора или измерений через точку (например, Прием.Пациент = &Пациент) на уровне СУБД вызывает неявные соединения и замедляет выполнение запроса. Если взаиморасчеты ведутся в разрезе субъектов, измерение с субъектом расчетов должно находиться непосредственно в регистре накопления.
  4. Блокировка интерфейса при навигации: Если каждый раз при перемещении курсора по списку стрелками с клавиатуры вызывать серверную процедуру синхронно, интерфейс программы начнет зависать.

Вариант 1. Получение остатка через серверную функцию с обработчиком ожидания

Разберем базовый вариант: при выборе строки в списке справочника на клиенте определяется ссылка на выбранный элемент, а расчет остатка выполняется отдельной серверной функцией без контекста формы (или с контекстом, если требуется доступ к реквизитам формы).

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

Посмотрим на пример клиентского и серверного кода формы списка:


&НаКлиенте
Процедура СписокПриАктивизацииСтроки(Элемент)
    // Сбрасываем предыдущий запланированный вызов, если пользователь быстро листает список
    ОтключитьОбработчикОжидания("ОбновитьОтображениеЗадолженности");
    
    // Подключаем однократный вызов с небольшой задержкой (0.2 секунды)
    ПодключитьОбработчикОжидания("ОбновитьОтображениеЗадолженности", 0.2, Истина);
КонецПроцедуры

&НаКлиенте
Процедура ОбновитьОтображениеЗадолженности()
    ТекущиеДанные = Элементы.Список.ТекущиеДанные;
    
    Если ТекущиеДанные = Неопределено Тогда
        Элементы.НадписьЗадолженность.Заголовок = "";
        Возврат;
    КонецЕсли;
    
    // Если справочник иерархический, исключаем расчет для групп
    Если СвойствоЕсть(ТекущиеДанные, "ЭтоГруппа") И ТекущиеДанные.ЭтоГруппа Тогда
        Элементы.НадписьЗадолженность.Заголовок = "";
        Возврат;
    КонецЕсли;
    
    СсылкаНаПациента = ТекущиеДанные.Ссылка;
    
    // Получаем структуру с рассчитанными данными с сервера
    ДанныеПоЗадолженности = ПолучитьДанныеПоЗадолженности(СсылкаНаПациента);
    
    СуммаДолга = ДанныеПоЗадолженности.Сумма;
    Валюта = ДанныеПоЗадолженности.Валюта;
    
    // Форматируем число для корректного отображения копеек и разделителей
    СуммаСтрокой = Формат(abs(СуммаДолга), "ЧДЦ=2; ЧГ=3,0; ЧН=0,00") + " " + Валюта;
    
    Если СуммаДолга = 0 Тогда
        Элементы.НадписьЗадолженность.ЦветТекстаЗаголовка = WebЦвета.Зеленый;
        Элементы.НадписьЗадолженность.Заголовок = "У пациента нет задолженности";
    ИначеЕсли СуммаДолга > 0 Тогда
        Элементы.НадписьЗадолженность.ЦветТекстаЗаголовка = WebЦвета.Красный;
        Элементы.НадписьЗадолженность.Заголовок = "Задолженность пациента: " + СуммаСтрокой;
    Иначе
        Элементы.НадписьЗадолженность.ЦветТекстаЗаголовка = WebЦвета.Синий;
        Элементы.НадписьЗадолженность.Заголовок = "Переплата (аванс): " + СуммаСтрокой;
    КонецЕсли;
КонецПроцедуры

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

&НаКлиенте
Функция СвойствоЕсть(Объект, ИмяСвойства)
    Возврат Объект.Свойство(ИмяСвойства);
КонецФункции

Вариант 2. Произвольный запрос в динамическом списке (рекомендуемый подход)

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

Проанализируем преимущества данного подхода:

  1. Платформа 1С считывает данные пачками по мере прокрутки списка пользователем.
  2. Полностью отсутствуют дополнительные серверные вызовы при перемещении по строкам.
  3. Поле задолженности можно вывести как в отдельную колонку таблицы, так и связать с надписью под таблицей через данные текущей строки.

Текст произвольного запроса для динамического списка выглядит следующим образом:


ВЫБРАТЬ
    СправочникПациенты.Ссылка КАК Ссылка,
    СправочникПациенты.ПометкаУдаления КАК ПометкаУдаления,
    СправочникПациенты.Код КАК Код,
    СправочникПациенты.Наименование КАК Наименование,
    ЕСТЬNULL(ОплатыОстатки.СуммаОстаток, 0) КАК Задолженность
ИЗ
    Справочник.Пациенты КАК СправочникПациенты
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОплатыПриемов.Остатки(&Период, ) КАК ОплатыОстатки
        ПО СправочникПациенты.Ссылка = ОплатыОстатки.Пациент

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

← На главную