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