Почему запрос в 1С не выбирает кредитовый остаток по счету 361, хотя в ОСВ он есть?

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

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

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

---

Выясняем причину: физическое хранение остатков в СУБД против ОСВ

Разработчик в первом сообщении пытается получить кредитовый остаток по счету 361 с отбором по конкретному документу расчетов (субконто «Счет на оплату покупателю»):


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

Несмотря на то, что в Оборотно-сальдовой ведомости бухгалтер видит сумму в колонке «Кредит», данный запрос возвращает пустую строку или NULL. В процессе отладки (сообщение 8) выясняется, что при выводе всех полей виртуальной таблицы сумма на самом деле находится в полях СуммаОстатокДт и СуммаРазвернутыйОстатокДт. Почему так происходит?

Дело в том, как платформа 1С:Предприятие работает с видом счета (Активный, Пассивный, Активно-пассивный):

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

Важно понимать: Оборотно-сальдовая ведомость — это отчет, созданный для удобства человека (бухгалтера). Логика отчета автоматически преобразует отрицательные остатки в положительные значения и «перебрасывает» их в противоположную колонку. Если вы видите сумму в кредите ОСВ на активном счете, в базе данных она почти наверняка лежит как отрицательный дебет. Именно поэтому запрос, обращающийся напрямую к СуммаОстатокКт, ничего не находил.

---

Что такое развернутое сальдо и почему оно важно?

Для счетов учета расчетов крайне важно анализировать остатки в разрезе всей аналитики. Если использовать обычные (свернутые) поля СуммаОстатокДт и СуммаОстатокКт, СУБД математически сложит все дебеты и кредиты.

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

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

---

Критические ошибки в исходном запросе автора

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

Ошибка №1. Фильтрация по строковому коду счета (Счет.Код = "361")

Использование текстового представления счета в условиях запроса — это плохая практика по нескольким причинам:

Ошибка №2. Обращение к субконто по индексу (Субконто3)

Обращение к полям Субконто1, Субконто2, Субконто3 напрямую без указания их типов — это «мина замедленного действия». Если в конфигурации изменится порядок субконто на счете (например, «Документы расчетов» переместят со второй позиции на третью или наоборот), запрос перестанет возвращать данные. Кроме того, СУБД не может оптимизировать план запроса, так как тип поля Субконто3 для нее остается неопределенным.

---

Как написать запрос правильно и надежно?

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

Для правильной фильтрации по субконто мы передадим в параметры виртуальной таблицы массив видов субконто. Это жестко типизирует наше условие.

Рассмотрим правильный вариант реализации на встроенном языке:


// 1. Создаем массив счетов, по которым хотим получить остатки.
// Избегаем поиска по коду в запросе. Находим счета через менеджер плана счетов.
МассивСчетов = Новый Массив;
МассивСчетов.Добавить(ПланыСчетов.Хозрасчетный.Покупатели); // Соответствует счету 361
Если ПолучитьФункциональнуюОпцию("ИспользоватьВалютныйУчет") Тогда
    МассивСчетов.Добавить(ПланыСчетов.Хозрасчетный.РасчетыВВалюте); // Соответствует счету 362
КонецЕсли;

// 2. Формируем массив видов субконто для типизации параметров виртуальной таблицы
МассивВидовСубконто = Новый Массив;
МассивВидовСубконто.Добавить(ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.ДокументыРасчетовСКонтрагентами);

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

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

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

---

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

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

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

← На главную