При разработке отчетов или доработке существующих механизмов в конфигурациях на базе обычных форм (таких как «Управление торговлей 10.3», «УПП 1.3» или «Комплексная автоматизация 1.1»), программисты часто сталкиваются с ситуацией, когда данные в документе визуально присутствуют, но программно получить их через обращение к реквизитам шапки не удается. Типичный пример — работа с документом ПриходныйКассовыйОрдер (ПКО) и попытка извлечь Статью движения денежных средств (СДДС).
В этой статье мы подробно разберем, почему реквизиты шапки могут быть пустыми, где на самом деле хранятся данные о платежах и как правильно обращаться к ним, чтобы избежать ошибок производительности и исключительных ситуаций.
Рассмотрим ситуацию: вы пытаетесь получить код статьи движения денежных средств, используя стандартную выборку документов. Код выглядит примерно так:
ВыборкаПКО = Документы.ПриходныйКассовыйОрдер.Выбрать(ДатаНачала, ДатаКонца);
Пока ВыборкаПКО.Следующий() Цикл
Сообщить(ВыборкаПКО.СтатьяДвиженияДенежныхСредств.Код); // Выводит пустую строку
КонецЦикла;
Проанализируем причину такого поведения. В универсальных конфигурациях 1С старого поколения документ ПКО спроектирован так, чтобы одним документом можно было отразить оплату по нескольким основаниям (например, по разным договорам или статьям). Для этого в документе предусмотрена табличная часть РасшифровкаПлатежа.
Важный нюанс: реквизит СтатьяДвиженияДенежныхСредств может существовать и в шапке документа, и в табличной части. Однако, в зависимости от выбранного ВидаОперации, данные могут записываться исключительно в таблицу. Например, при операции «Оплата от покупателя» система игнорирует реквизит шапки и работает только с расшифровкой. Реквизит в шапке часто остается для обратной совместимости или специфических видов операций (например, «Прочий приход»), где аналитика по статьям не детализируется.
Самый быстрый способ получить значение — обратиться к первой строке табличной части. Это сработает, если в документе всегда заполнена хотя бы одна строка расшифровки. Разберем программный код:
Если ВыборкаПКО.РасшифровкаПлатежа.Количество() > 0 Тогда
Статья = ВыборкаПКО.РасшифровкаПлатежа[0].СтатьяДвиженияДенежныхСредств;
Сообщить("Статья: " + Статья.Код);
КонецЕсли;
Здесь мы используем индекс [0] для доступа к первой строке коллекции. Внимание: всегда проверяйте количество строк перед обращением по индексу, иначе при наличии пустого документа система выдаст критическую ошибку «Индекс находится вне границ диапазона».
Если же документ может содержать несколько строк с разными статьями, нам необходимо организовать обход коллекции:
Для каждого СтрокаРасшифровки Из ВыборкаПКО.РасшифровкаПлатежа Цикл
Если ЗначениеЗаполнено(СтрокаРасшифровки.СтатьяДвиженияДенежныхСредств) Тогда
Сообщить("Найдена статья: " + СтрокаРасшифровки.СтатьяДвиженияДенежныхСредств.Наименование);
КонецЕсли;
КонецЦикла;
Использование метода Выбрать() в циклах — это «плохой тон» в разработке на платформе 1С. Этот метод тянет из базы данных объект целиком (включая все реквизиты, все табличные части и двоичные данные), что крайне неэффективно для отчетов. Проанализируем правильный подход с использованием объекта Запрос.
Для получения СДДС нам лучше всего обратиться напрямую к виртуальной таблице или к табличной части документа. Посмотрим на пример запроса:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПКО_Расшифровка.Ссылка КАК ДокументСсылка,
| ПКО_Расшифровка.СтатьяДвиженияДенежныхСредств КАК СтатьяДДС,
| ПКО_Расшифровка.СтатьяДвиженияДенежныхСредств.Код КАК СтатьяКод
|ИЗ
| Документ.ПриходныйКассовыйОрдер.РасшифровкаПлатежа КАК ПКО_Расшифровка
|ГДЕ
| ПКО_Расшифровка.Ссылка.Дата МЕЖДУ &ДатаНачала И &ДатаКонца
| И ПКО_Расшифровка.Ссылка.Проведен = ИСТИНА";
Запрос.УстановитьПараметр("ДатаНачала", ДатаНачала);
Запрос.УстановитьПараметр("ДатаКонца", ДатаКонца);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
// Теперь данные доступны напрямую из выборки запроса
Сообщить("Документ: " + Выборка.ДокументСсылка + " - Статья: " + Выборка.СтатьяКод);
КонецЦикла;
Преимущества этого метода:
Если ваша задача — создать полноценный отчет, лучшим решением будет использование Системы компоновки данных (СКД). Многие начинающие разработчики боятся СКД, но именно она автоматически решает проблему «вложенных» данных.
В схеме компоновки достаточно выбрать в качестве источника таблицу Документ.ПриходныйКассовыйОрдер.РасшифровкаПлатежа. Платформа сама выполнит необходимые соединения (Join) на уровне SQL-запроса. Вам не придется писать циклы и проверять наличие строк — СКД сгенерирует результат автоматически.
Разберем еще один важный момент, упомянутый в обсуждении: получение данных «через точку» на клиенте. В управляемом приложении или при работе с формами важно помнить, что обращение типа Ссылка.ИмяРеквизита вызывает неявный серверный вызов.
Если вы находитесь в модуле формы и пытаетесь получить данные табличной части документа, который не открыт на экране, через его ссылку — это приведет к значительным задержкам. Проанализируем правило: любое получение данных объекта должно происходить на сервере, предпочтительно в одном запросе. Никогда не обращайтесь к табличным частям через ссылку в цикле на стороне клиента.
Выясним основные правила работы с документами типа ПКО в УТ 10.3:
РасшифровкаПлатежа, если реквизит шапки пуст.Выбрать().Используя эти подходы, вы сможете создавать надежные и быстрые механизмы обработки кассовых документов, которые не будут выдавать ошибок при изменении состава платежа или очистке реквизитов шапки.