При разработке отчетов и обработок в среде 1С:Предприятие 7.7 программисты часто сталкиваются с необходимостью анализа корреспонденции счетов. Работа с механизмом бухгалтерских итогов в «семерке» имеет ряд специфических особенностей. Одна из наиболее распространенных проблем — когда цикл обхода корреспондирующих счетов ВыбратьКорСчета() визуально написан правильно, но при выполнении кода программа просто «проскакивает» его, не выдавая никаких результатов и не выводя ошибок. В рамках этой статьи мы подробно разберем, почему возникает эта проблема, как устроен механизм расчета сквозных оборотов и как правильно построить обход итогов с учетом аналитики.
Проанализируем исходный код, с которым столкнулся автор темы. В его алгоритме инициализируется объект БухгалтерскиеИтоги, накладывается фильтр по субконто «Плательщик», а затем вызывается метод ВыполнитьЗапрос():
БИ = СоздатьОбъект("БухгалтерскиеИтоги");
БИ.ИспользоватьСубконто("Плательщик");
БИ.ВключатьСубсчета(1, 1);
БИ.ВыполнитьЗапрос(НачДата, КонДата, Счет);
БИ.ВыбратьСчета();
Пока БИ.ПолучитьСчет() = 1 Цикл
БИ.ВыбратьКорСчета(1);
Пока БИ.ПолучитьКорСчет() = 1 Цикл
Сообщить("Наз==");
КонецЦикла;
КонецЦикла;
При запуске такого кода цикл по корреспондирующим счетам игнорируется. Главная причина кроется в параметрах метода ВыполнитьЗапрос(). Давайте обратимся к его синтаксису:
ВыполнитьЗапрос(НачалоПериода, КонецПериода, Счет, КоррСчет, Валюта, ТипИтогов, Периодичность, ТипСуммы)
Особое внимание следует уделить шестому параметру — ТипИтогов. По умолчанию, если этот параметр не указан явным образом, платформа принимает его равным 1. Давайте разберем, что означают значения этого параметра:
ВыбратьКорСчета() в таком случае всегда возвращает 0.Для того чтобы решить проблему пустой выборки корсчетов, нам необходимо явно указать тип итогов 2 или 3 при вызове запроса.
Рассмотрим, как должен выглядеть правильный вызов метода. Если в отчете нам нужны только обороты корреспонденции (без вывода начальных и конечных остатков по основному счету), мы можем использовать тип итогов 2. Если нужны и остатки, и корсчета — выбираем 3.
Посмотрим на пример правильной инициализации запроса:
// Передаем шестым параметром значение 3 для получения полной картины
Если БИ.ВыполнитьЗапрос(НачДата, КонДата, Счет, , , 3) = 0 Тогда
Предупреждение("Не удалось выполнить запрос по бухгалтерским итогам!");
Возврат;
EndIf;
Обратите внимание на пустые запятые. Мы пропускаем параметры КоррСчет и Валюта, оставляя их по умолчанию, но обязательно позиционируем шестой параметр.
Вторая важная деталь в коде автора — строка БИ.ИспользоватьСубконто("Плательщик");. Когда мы накладываем фильтр по субконто или просто указываем его использование в запросе, структура выборки объекта БухгалтерскиеИтоги кардинально меняется. Итоги начинают строиться с учетом иерархии аналитики.
Если мы объявили использование субконто, но в коде пытаемся сразу выполнить обход по счетам (БИ.ВыбратьСчета()), платформа может вернуть пустой результат или отработать некорректно. Нам нужно определиться со стратегией обхода данных. Разберем два сценария:
Сценарий А: Нам действительно нужен разрез по плательщикам. В этом случае перед обходом счетов мы обязаны открыть цикл по субконто. Посмотрим на правильную структуру вложенности циклов:
БИ = СоздатьОбъект("БухгалтерскиеИтоги");
БИ.ИспользоватьСубконто("Плательщик");
БИ.ВыполнитьЗапрос(НачДата, КонДата, Счет, , , 3);
// 1. Первый уровень обхода - Субконто (Плательщики)
БИ.ВыбратьСубконто(1);
Пока БИ.ПолучитьСубконто(1) = 1 Цикл
Сообщить("Плательщик: " + БИ.Субконто(1));
// 2. Второй уровень обхода - Счета для текущего субконто
БИ.ВыбратьСчета();
Пока БИ.ПолучитьСчет() = 1 Цикл
Сообщить("--- Счет: " + БИ.Счет);
// 3. Третий уровень обхода - Корреспондирующие счета
БИ.ВыбратьКорСчета(1);
Пока БИ.ПолучитьКорСчет() = 1 Цикл
Сообщить("------ КорСчет: " + БИ.КорСчет + " Сумма: " + БИ.КорДО());
КонецЦикла;
КонецЦикла;
КонецЦикла;
Сценарий Б: Аналитика по плательщикам в данном отчете не требуется. Если нам нужно просто получить общие обороты по счету в разрезе его корреспонденций без детализации по конкретным контрагентам, строку с субконто нужно полностью удалить из кода. Без нее обход счетов заработает напрямую:
БИ = СоздатьОбъект("БухгалтерскиеИтоги");
// Строку ИспользоватьСубконто удалили
БИ.ВыполнитьЗапрос(НачДата, КонДата, Счет, , , 3);
БИ.ВыбратьСчета();
Пока БИ.ПолучитьСчет() = 1 Цикл
Сообщить("Счет: " + БИ.Счет);
БИ.ВыбратьКорСчета(1);
Пока БИ.ПолучитьКорСчет() = 1 Цикл
Сообщить("--- КорСчет: " + БИ.КорСчет);
КонецЦикла;
КонецЦикла;
Проанализируем замечание из сообщения 6 форума. Автор исходного кода использовал строковый идентификатор вида субконто: БИ.ИспользоватьСубконто("Плательщик");.
Платформа 1С 7.7 позволяет передавать имя субконто строкой, однако этот подход таит в себе скрытые угрозы:
"Контрагенты" или "Договоры", а не "Плательщик". Название «Плательщик» может быть лишь именем реквизита в каком-то документе, но не самим видом субконто на счете.Для повышения надежности кода настоятельно рекомендуется передавать вид субконто через предопределенное системное значение ВидыСубконто:
// Надежный способ обращения к метаданным
БИ.ИспользоватьСубконто(ВидыСубконто.Контрагенты);
Если на счете настроено несколько видов субконто (например, 1-й разрез — Контрагенты, 2-й разрез — Договоры), мы можем позиционировать их последовательно:
БИ.ИспользоватьСубконто(ВидыСубконто.Контрагенты, , 1); // Первое субконто (только по группам)
БИ.ИспользоватьСубконто(ВидыСубконто.Договоры, , 1); // Второе субконто
Часто начинающие программисты допускают ошибку, пытаясь получить сумму проводки внутри цикла по корсчетам с помощью стандартных методов БИ.ДО() (Дебетовый оборот) или БИ.КО() (Кредитовый оборот). Эти методы внутри цикла по корсчетам будут продолжать возвращать общий оборот по основному счету, игнорируя конкретную корреспонденцию.
Для получения финансовых показателей именно в разрезе корреспондирующих счетов необходимо использовать специализированные методы объекта БухгалтерскиеИтоги:
БИ.КорДО() — возвращает дебетовый оборот по счету в корреспонденции с текущим корреспондирующим счетом (сумма проводок Дт [Счет] - Кт [КорСчет]).БИ.КорКО() — возвращает кредитовый оборот по счету в корреспонденции с текущим корреспондирующим счетом (сумма проводок Дт [КорСчет] - Кт [Счет]).БИ.КорОБ() — совокупный оборот между основным и корреспондирующим счетом.Рассмотрим практический пример вывода оборотов в таблицу:
БИ = СоздатьОбъект("БухгалтерскиеИтоги");
СчетАнализа = СчетПоКоду("51"); // Расчетный счет
БИ.ВыполнитьЗапрос(НачДата, КонДата, СчетАнализа, , , 3);
БИ.ВыбратьСчета();
Пока БИ.ПолучитьСчет() = 1 Цикл
БИ.ВыбратьКорСчета(1);
Пока БИ.ПолучитьКорСчет() = 1 Цикл
СуммаПоступления = БИ.КорДО(); // Дт 51 - Кт КорСчет
СуммаСписания = БИ.КорКО(); // Дт КорСчет - Кт 51
Если (СуммаПоступления > 0) Или (СуммаСписания > 0) Тогда
Сообщить("Корреспонденция счетом " + БИ.КорСчет.Код + ":");
Сообщить(" Поступило: " + Шаблон("[СуммаПоступления] руб."));
Сообщить(" Списано: " + Шаблон("[СуммаСписания] руб."));
КонецЕсли;
КонецЦикла;
КонецЦикла;
В сложных бухгалтерских отчетах иногда требуется узнать не просто код корреспондирующего счета, но и субконто, которое закреплено за этим корсчетом. Например, при списании материалов на затраты (Дт 20 - Кт 10) нам может потребоваться узнать, на какую конкретно номенклатурную группу (субконто счета 20) ушли материалы с кредита счета 10.
Для решения этой задачи в 1С 7.7 существует метод ИспользоватьКорСубконто(). Его использование аналогично обычному субконто, но применяется оно к корреспондирующей стороне:
БИ = СоздатьОбъект("БухгалтерскиеИтоги");
// Задаем аналитику для основного счета (например, Номенклатура на 10 счете)
БИ.ИспользоватьСубконто(ВидыСубконто.Материалы);
// Задаем аналитику для корреспондирующего счета (например, Подразделение на 20 счете)
БИ.ИспользоватьКорСубконто(ВидыСубконто.Подразделения);
БИ.ВыполнитьЗапрос(НачДата, КонДата, СчетПоКоду("10"), , , 3);
БИ.ВыбратьСубконто(1);
Пока БИ.ПолучитьСубконто(1) = 1 Цикл
// Обходим наши материалы
БИ.ВыбратьСчета();
Пока БИ.ПолучитьСчет() = 1 Цикл
БИ.ВыбратьКорСчета();
Пока БИ.ПолучитьКорСчет() = 1 Цикл
// Теперь мы можем обойти аналитику корсчета!
БИ.ВыбратьКорСубконто(1);
Пока БИ.ПолучитьКорСубконто(1) = 1 Цикл
Сообщить("Материал: " + БИ.Субконто(1) +
" списан на подразделение: " + БИ.КорСубконто(1) +
" Сумма: " + БИ.КорКО());
КонецЦикла;
КонецЦикла;
КонецЦикла;
КонецЦикла;
Использование связки основного и корреспондирующего субконто позволяет получать мощные интерактивные отчёты прямо из регистров бухгалтерии, минуя необходимость делать тяжелые выборки по операциям и проводкам вручную.
Если у вас не выбираются корсчета в 1С 7.7, проверьте следующие моменты по нашему чек-листу:
ВыполнитьЗапрос? Он должен быть равен 2 или 3.ИспользоватьСубконто(), убедитесь, что вы делаете выборку субконто (ВыбратьСубконто() и цикл ПолучитьСубконто()) перед тем, как переходить к счетам и корсчетам.ВидыСубконто.КорДО() / КорКО()) внутри цикла по корреспондирующим счетам?Соблюдение этих простых правил проектирования запросов к бухгалтерским итогам гарантирует быструю и корректную работу ваших отчетов без лишней нагрузки на базу данных 1С:Предприятия 7.7.