При разработке и сопровождении конфигураций на платформе 1С:Предприятие 8 часто возникает необходимость скорректировать аналитический учет на счетах. Одна из типичных задач — изменить последовательность субконто на определенном счете (например, сделать так, чтобы первым субконто на счете 60.01 были «Контрагенты», а вторым — «Договоры», или наоборот).
На первый взгляд задача кажется тривиальной, однако изменение порядка субконто затрагивает механизмы физического хранения данных в СУБД, а также логику работы запросов и алгоритмов проведения документов. В этой статье мы подробно разберем, от чего зависит порядок субконто в регистре бухгалтерии, как его изменить интерактивно или программно, и как предотвратить искажение данных в уже существующих проводках.
Прежде чем переходить к практическим действиям, давайте разберем внутреннее устройство платформы. На уровне базы данных СУБД регистр бухгалтерии хранит значения субконто в физических колонках с жестко заданными именами, такими как СубконтоДт1, СубконтоДт2, СубконтоКт1 и так далее.
Когда мы настраиваем счет в плане счетов, порядок строк в табличной части ВидыСубконто определяет, под каким физическим индексом будут записываться данные:
Субконто1 в таблицах движений и итогов.Субконто2.Субконто3.Если мы просто поменяем местами строки субконто на счете (например, сделаем «Контрагенты» первым субконто вместо второго) в работающей информационной базе, физические данные в базе данных автоматически не перезапишутся.
В результате старые проводки, которые были записаны до изменения структуры, «перепутаются» при формировании стандартных отчетов (например, Оборотно-сальдовой ведомости по счету). Договоры начнут отображаться в колонке контрагентов, а контрагенты — в колонке договоров. Поэтому к изменению порядка субконто нужно подходить максимально аккуратно и строго следовать технологическому процессу.
Если счета и виды субконто добавляются непосредственно пользователями или администраторами в режиме предприятия (без внесения изменений в конфигураторе), изменить порядок следования аналитики можно двумя способами.
Способ 1. Интерактивное перемещение в интерфейсе
В форме счета найдем табличную часть ВидыСубконто. Если разработчики конфигурации не вывели стандартные командные кнопки со стрелками («Вверх» / «Вниз»), мы можем воспользоваться стандартными сочетаниями клавиш платформы 1С:
Также во многих управляемых формах работает обычное перетаскивание строк таблицы при помощи удержания левой кнопки мыши (Drag-and-Drop).
Способ 2. Программный сдвиг строк (с помощью внешней обработки)
Если интерактивно изменить порядок не удается (например, элементы управления заблокированы программно), мы можем написать небольшую процедуру во внешней обработке, которая изменит порядок строк в табличной части объекта плана счетов.
Для этого мы получаем объект нужного счета, находим его строку по конкретному виду субконто, используем метод Сдвинуть() табличной части и записываем изменения. Рассмотрим пример кода:
// Определим счет, порядок субконто которого необходимо изменить
СчетСсылка = ПланыСчетов.Хозрасчетный.НайтиПоКоду("60.01");
СчетОбъект = СчетСсылка.ПолучитьОбъект();
ТабЧасть = СчетОбъект.ВидыСубконто;
// Находим вид субконто, который должен стать первым (например, Контрагенты)
ВидАналитики = ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Контрагенты;
СтрокаСубконто = ТабЧасть.Найти(ВидАналитики, "ВидСубконто");
Если СтрокаСубконто <> Неопределено Тогда
ТекущийИндекс = ТабЧасть.Индекс(СтрокаСубконто);
// Если строка не на первом месте (индекс > 0), сдвигаем ее в самый верх
Если ТекущийИндекс > 0 Тогда
ШагСдвига = -ТекущийИндекс; // Отрицательное число сдвигает строку вверх
ТабЧасть.Сдвинуть(ТекущийИндекс, ШагСдвига);
// Записываем измененный объект плана счетов
СчетОбъект.Записать();
Сообщить("Порядок субконто для счета " + СчетСсылка + " успешно изменен!");
КонецЕсли;
КонецЕсли;
После того как мы изменили порядок строк в плане счетов, новые документы будут формировать движения правильно. Однако исторические данные (проводки прошлых периодов) все еще хранятся в старом формате. Нам необходимо принудительно переписать движения всех документов, которые задействуют измененный счет.
Для этого мы можем воспользоваться стандартной процедурой группового перепроведения документов за весь период ведения учета. Если документов в базе слишком много и перепроводить их целиком нежелательно (например, из-за изменения себестоимости или партионного учета), мы можем программно перезаписать только наборы записей регистра бухгалтерии по нужному счету без повторного выполнения тяжелых расчетов документов.
Рассмотрим пример алгоритма выборочной перезаписи движений регистра бухгалтерии:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| ХозрасчетныйДвижения.Регистратор КАК Регистратор
|ИЗ
| РегистрБухгалтерии.Хозрасчетный КАК ХозрасчетныйДвижения
|ГДЕ
| (ХозрасчетныйДвижения.СчетДт = &СчетОбновления
| ИЛИ ХозрасчетныйДвижения.СчетКт = &СчетОбновления)";
Запрос.УстановитьПараметр("СчетОбновления", СчетСсылка);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
// Получаем набор записей регистра по конкретному документу-регистратору
НаборЗаписей = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(Выборка.Регистратор);
НаборЗаписей.Прочитать();
// При перезаписи набора платформа автоматически перераспределит
// значения субконто в физические колонки согласно новому порядку на счете!
Если НаборЗаписей.Количество() > 0 Тогда
НаборЗаписей.Записать();
КонецЕсли;
КонецЦикла;
Одной из частых причин возникновения проблем при изменении порядка субконто является некорректно написанный программный код в модулях проведения документов. Если разработчик обращается к субконто напрямую по индексам, например:
// ВАЖНО: Это пример ПЛОХОЙ практики программирования!
НоваяСтрока.СубконтоКт1 = Договор.Владелец; // Ожидаем, что первое субконто всегда Контрагент
НоваяСтрока.СубконтоКт2 = Договор; // Ожидаем, что второе субконто всегда Договор
Любое изменение порядка субконто пользователем в режиме предприятия мгновенно приведет к ошибкам в проведении. Программа продолжит записывать владельца договора в первое поле, а договор во второе, невзирая на то, что на самом счете их порядок изменился.
Правильный подход заключается в заполнении субконто по его типу или виду с помощью метода Вставить() коллекции Субконто. В таком случае платформа самостоятельно определит, под каким индексом зарегистрирован данный вид субконто на счете в текущий момент времени, и запишет его в нужное физическое поле:
// ПРАВИЛЬНЫЙ ПОДХОД: Платформа сама определит индексы и распределит значения
НоваяСтрока.СубконтоКт.Вставить(ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Контрагенты, Договор.Владелец);
НоваяСтрока.СубконтоКт.Вставить(ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Договоры, Договор);
В типовых конфигурациях (например, в «1С:Бухгалтерия предприятия») для этих целей разработан специальный общий модуль, вызов которого выглядит следующим образом:
БухгалтерскийУчет.УстановитьСубконто(Проводка.СчетКт, Проводка.СубконтоКт, "Контрагенты", Реквизиты.Контрагент);
БухгалтерскийУчет.УстановитьСубконто(Проводка.СчетКт, Проводка.СубконтоКт, "Договоры", Реквизиты.Договор);
Иногда разработчики сталкиваются со странным поведением системы в процессе отладки. Например, после успешного изменения порядка субконто и перезаписи проводок, при выгрузке набора записей регистра в таблицу значений методом Выгрузить(), колонки СубконтоДт1 / СубконтоКт1 по-прежнему отображаются в отладчике «перепутанными».
Проанализируем эту ситуацию. Согласно официальной спецификации платформы «1С:Предприятие 8», при выгрузке набора записей регистра бухгалтерии номера в названиях колонок полученной таблицы значений (например, СубконтоКт1, СубконтоКт2) могут не совпадать с индексами видов субконто на счете.
Это связано с тем, что таблица значений движений формируется динамически. Чтобы точно определить, какому именно субконто соответствует колонка в конкретной строке таблицы значений, всегда необходимо сопоставлять данные колонки СубконтоКт1 со значением в системной колонке ВидСубконтоКт1 в той же самой строке. Прямая привязка к числовому индексу при работе с таблицей выгрузки движений является распространенной логической ошибкой.
Если ваша единственная цель изменения порядка субконто — это вывод информации в отчеты (или печатные формы) в определенной последовательности, то менять структуру плана счетов и перезаписывать движения всей базы данных вообще не требуется.
В параметрах виртуальных таблиц регистра бухгалтерии (таких как Остатки, Обороты, ОстаткиИОбороты) присутствует специальный параметр Субконто. Если мы передадим туда массив видов субконто в строго определенной нами последовательности, то в полях выборки запроса поля Субконто1, Субконто2 распределятся в соответствии с переданным массивом, независимо от настроек плана счетов:
МассивСубконто = Новый Массив;
// Задаем нужный порядок вывода в отчете
МассивСубконто.Добавить(ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Контрагенты);
МассивСубконто.Добавить(ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Договоры);
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ХозрасчетныйОстатки.Субконто1 КАК Контрагент,
| ХозрасчетныйОстатки.Субконто2 КАК Договор,
| ХозрасчетныйОстатки.СуммаОстаток КАК СуммаОстаток
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.Остатки( , Счет = &Счет, &ВидыСубконто, ) КАК ХозрасчетныйОстатки";
Запрос.УстановитьПараметр("Счет", ПланыСчетов.Хозрасчетный.НайтиПоКоду("60.01"));
Запрос.УстановитьПараметр("ВидыСубконто", МассивСубконто);
Результат = Запрос.Выполнить();
Этот способ является наиболее безопасным и производительным, так как исключает необходимость монопольного изменения структуры метаданных и ресурсоемкого перепроведения документов в информационной базе.