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