Мы часто сталкиваемся с ситуациями, когда данные в системе 1С ведут себя непредсказуемо. Одна из таких проблем, способная поставить в тупик даже опытного специалиста, — это исчезновение аналитики (субконто) в стандартных бухгалтерских отчетах. Представьте ситуацию: вы открываете оборотно-сальдовую ведомость или карточку счета и видите суммы, но поле субконто пустое. При этом, если открыть сам документ-регистратор и нажать кнопку Дт-Кт, вы четко видите, что аналитика заполнена корректно. Стандартное перепроведение документов запрещено (например, закрытый период), а пересчет итогов через администрирование не дает результата.
В этой статье мы подробно разберем причины такого поведения платформы, проанализируем архитектуру хранения данных регистра бухгалтерии и разработаем надежный программный метод исправления ошибки без перепроведения документов.
Чтобы понять, как решать проблему, нам нужно разобраться, как 1С хранит бухгалтерские данные. Регистр бухгалтерии — это сложный объект, который на уровне базы данных (SQL) представлен не одной таблицей, и часто полезно проанализировать размер таблицы SQL базы 1С для понимания масштабов данных.
Проблема, описанная в теме, заключается в рассинхронизации этих таблиц. В движениях ссылки на субконто есть, но в таблицу итогов они "не доехали" или записались некорректно. Это может произойти по разным причинам: сбой при обновлении, некорректная выгрузка РИБ (распределенных информационных баз), ошибки СУБД или "битые" ссылки на виды субконто в метаданных.
Стандартная процедура "Пересчет итогов" в режиме "Тестирование и исправление" просто заново суммирует данные. Но если сама связь между записью в таблице движений и механизмом расчета итогов нарушена (например, платформа "не видит", что поле в базе данных соответствует текущему виду субконто), пересчет не поможет. В самых запущенных случаях, когда повреждены сами ссылки, может потребоваться универсальное удаление движений по битым ссылкам.
Первое, что приходит в голову программисту — прочитать набор записей по регистратору и тут же его записать. Казалось бы, это должно заставить платформу обновить таблицы итогов.
// Попытка решения "в лоб"
Набор = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
Набор.Отбор.Регистратор.Установить(СсылкаНаДокумент);
Набор.Прочитать();
Набор.Записать();
Однако на практике это часто не срабатывает. Платформа 1С содержит механизмы оптимизации: если она видит, что данные в наборе не изменились (свойство модифицированности не установлено), реальная запись в базу данных (SQL UPDATE/INSERT) может не произойти, либо произойдет частичное обновление, которое не затронет структуру итогов должным образом.
Как выяснилось в ходе обсуждения проблемы, наиболее действенный метод — это имитация удаления старых записей и ввода абсолютно новых. Это заставляет платформу сбросить кэши и заново сформировать записи в таблицах итогов, корректно сопоставив значения субконто с настройками Плана счетов.
Рассмотрим алгоритм, который гарантированно обновляет данные:
Рассмотрим код обработки, который реализует этот подход:
Процедура ИсправитьПроводкиДокумента(ДокументСсылка)
// 1. Создаем набор и читаем текущие движения
НаборЗаписей = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(ДокументСсылка);
НаборЗаписей.Прочитать();
// Если движений нет, нечего исправлять
Если НаборЗаписей.Количество() = 0 Тогда
Возврат;
КонецЕсли;
// 2. Выгружаем данные в таблицу значений, чтобы сохранить их "как есть"
ТаблицаДвижений = НаборЗаписей.Выгрузить();
// 3. Очищаем старый набор и записываем пустой набор
// Это физически удаляет записи из БД, очищая и таблицу итогов
НаборЗаписей.Очистить();
НаборЗаписей.Записать();
// 4. Создаем НОВЫЙ набор записей (важный момент для сброса контекста)
НовыйНабор = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
НовыйНабор.Отбор.Регистратор.Установить(ДокументСсылка);
// 5. Загружаем сохраненные данные
НовыйНабор.Загрузить(ТаблицаДвижений);
// Установка режима загрузки (подробнее об этом ниже)
НовыйНабор.ОбменДанными.Загрузка = Истина;
// 6. Записываем восстановленные данные
НовыйНабор.Записать();
КонецПроцедуры
При реализации программной перезаписи мы сталкиваемся с важнейшим выбором: использовать режим ОбменДанными.Загрузка = Истина или нет. Давайте проанализируем последствия каждого варианта, так как ошибка здесь может привести к искажению учета.
Если мы не устанавливаем ОбменДанными.Загрузка = Истина, платформа воспринимает запись набора так, будто пользователь вручную проводит документ или вводит операцию.
Плюсы:
Минусы и риски:
При ОбменДанными.Загрузка = Истина запись происходит "технически", напрямую в таблицы, минуя большинство проверок и бизнес-логику.
Плюсы:
Минусы и риски:
Чтобы избежать проблем с порядком субконто и одновременно не испортить исторические данные пересчетом, мы рекомендуем усовершенствовать алгоритм. Перед записью данных необходимо программно проверить и при необходимости переупорядочить субконто в соответствии с актуальными метаданными.
Рассмотрим, как это можно реализовать концептуально:
Субконто1, Субконто2, Субконто3 так, чтобы они соответствовали видам.ОбменДанными.Загрузка = Истина.Такой подход гарантирует, что значения попадут в нужные колонки SQL-таблиц (и таблицы итогов построятся верно), но при этом мы не затронем суммы и не вызовем срабатывание "свежей" бизнес-логики программы.
Если проблема носит массовый характер или после выполнения вышеуказанной обработки отчеты все еще ведут себя странно, необходимо выполнить полный регламент обслуживания базы данных.
Последовательность действий:
Важно: Реструктуризация — процесс долгий, но именно он помогает, когда нарушена структура хранения данных на уровне СУБД, что часто бывает причиной исчезновения аналитики после некорректных обновлений или сбоев РИБ.