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