Как избежать появления NULL в субконто регистра бухгалтерии при обмене данными в режиме Загрузка = Истина?

Программист 1С v8.3 (Управляемые формы) 1С:ERP Управление предприятием Бухгалтерский учет IT и автоматизация бизнеса
← На главную

При переносе бухгалтерских проводок между конфигурациями 1С (например, из специализированной базы расчета зарплаты в ERP или Бухгалтерию предприятия) разработчики часто сталкиваются с неприятным эффектом: в оборотно-сальдовой ведомости базы-приемника по некоторым счетам «раздваиваются» строки с пустыми субконто. При этом остатки по дебету и кредиту не закрываются между собой, хотя визуально аналитика выглядит абсолютно одинаково — пустые поля. Выясняется, что в одном случае значением является Неопределено (или пустая ссылка), а в другом — физический NULL на уровне базы данных СУБД.

В этой статье мы подробно разберем, почему возникает эта проблема, как на нее влияет свойство ОбменДанными.Загрузка = Истина, и рассмотрим практические варианты ее решения как на уровне правил обмена данными, так и программными средствами.

Физическая структура регистра бухгалтерии в СУБД

Для того чтобы понять природу возникновения проблемы, проанализируем устройство таблиц регистра бухгалтерии на уровне базы данных SQL. Платформа «1С:Предприятие» хранит движения регистра не в одной плоской таблице, а разделяет их на несколько связанных сущностей:

  1. Основная таблица движений (например, _AccRg). Здесь хранятся ключевые реквизиты проводки: период, регистратор, номер строки, счета дебета и кредита, валюта, количество, сумма.
  2. Вспомогательная реальная таблица значений субконто (например, _AccRgED). В ней хранятся конкретные аналитические разрезы для каждой проводки. Записи в ней связаны с основной таблицей по полям периода, регистратора и номера строки. Количество строк в этой таблице зависит от того, сколько субконто определено для счета в проводке и заполнены ли они.

При формировании бухгалтерских отчетов или обращении к виртуальным таблицам (например, ОстаткиИОбороты) платформа выполняет левое соединение (LEFT JOIN) основной таблицы движений со вспомогательной таблицей значений субконто. Если в таблице значений субконто отсутствует запись для конкретного разреза аналитики, результатом левого соединения становится значение NULL.

Различие в поведении платформы при разных режимах записи

Выясним причину, почему при обычном проведении документов в пользовательском режиме аналитика заполняется корректно, а при обмене данными возникает сбой. Все дело во флаге ОбменДанными.Загрузка:

  1. Режим ОбменДанными.Загрузка = Ложь (Обычная запись):
    При записи набора проводок платформа производит валидацию и постобработку данных. Для каждого счета проверяется состав субконто. Если у счета определены виды субконто (например, Контрагенты, Договоры, Документы расчетов), но в проводке они не были заполнены, платформа принудительно генерирует строки в физической таблице значений субконто со значением Неопределено или пустой ссылкой соответствующего типа. Благодаря этому при последующем соединении таблиц в запросах всегда возвращается корректное пустое значение, а не NULL.
  2. Режим ОбменДанными.Загрузка = Истина (Режим загрузки данных):
    Этот режим предназначен для максимально быстрого импорта данных «как есть». Платформа отключает все проверки, приведения типов, автозаполнения и триггеры. Если в загружаемом файле XML отсутствовали данные по пустым субконто, платформа запишет проводку в основную таблицу, а во вспомогательную таблицу значений субконто не запишет вообще ничего. В итоге при построении отчетов мы получаем тот самый разрушительный NULL.

Поскольку при обмене данными через конвертацию (КД 2.1 или КД 3.0) штатный XML-сериализатор выгружает пустые значения и значения с типом Неопределено как отсутствующие узлы, в базу-приемник они приходят в виде пустых коллекций. Рассмотрим, как решить эту проблему несколькими способами.

Решение 1. Принудительное заполнение пустых субконто при выгрузке (ПКС в КД 2.1)

Самый логичный путь — настроить правила обмена так, чтобы в файл выгрузки попадали явные значения пустых субконто. Для этого проанализируем обработчики событий в правилах конвертации свойств (ПКС) для коллекции субконто регистра бухгалтерии.

В ПКС для субконто (например, СубконтоДт и СубконтоКт) мы можем программно инициализировать коллекцию перед непосредственной выгрузкой данных. Пример кода для обработчика ПередВыгрузкой свойства:


// Проверим, заполнены ли субконто у счета дебета
Для Каждого ВидСубконто Из НомерПроводки.СчетДт.ВидыСубконто Цикл
    КлючСубконто = ВидСубконто.ВидСубконто;
    Если Не НомерПроводки.СубконтоДт.Свойство(КлючСубконто) Тогда
        // Принудительно вставляем пустое значение Неопределено
        НомерПроводки.СубконтоДт.Вставить(КлючСубконто, Неопределено);
    КонецЕсли;
КонецЦикла;

Аналогичный код необходимо написать и для субконто кредита СубконтоКт. При таком подходе в XML-файл выгрузки будут записаны явные указания видов субконто со значениями, которые платформа-приемник сможет корректно обработать даже в режиме Загрузка = Истина.

Решение 2. Программная перезапись набора в режиме Загрузка = Ложь (После загрузки)

Если по каким-то причинам изменить правила выгрузки на стороне источника невозможно, мы можем скорректировать поведение при загрузке. Нам потребуется обработать загруженный документ в базе-приемнике. Однако напрямую в обработчике ПослеЗагрузки ПКО документа вызывать перепроведение или запись движений не рекомендуется, так как это сильно замедлит процесс импорта данных.

Вместо этого мы применим методику отложенной перезаписи наборов движений. Разберем этот алгоритм по шагам:

Шаг 1. В обработчике ПослеЗагрузки ПКО документа собираем ссылки на все загруженные документы в специальный массив параметров:


Если Не Параметры.Свойство("ДокументыДляИсправленияСубконто") Тогда
    Параметры.Вставить("ДокументыДляИсправленияСубконто", Новый Массив);
КонецЕсли;

Параметры.ДокументыДляИсправленияСубконто.Добавить(Объект.Ссылка);

Шаг 2. В глобальном обработчике конвертации ПослеЗагрузкиДанных (который выполняется один раз в самом конце, когда весь файл обмена уже прочитан и все транзакции завершены) мы обходим накопленный массив документов и перезаписываем их движения в обычном режиме:


Если Параметры.Свойство("ДокументыДляИсправленияСубконто") Тогда
    Для Каждого СсылкаДок Из Параметры.ДокументыДляИсправленияСубконто Цикл
        // Создаем набор записей для регистра бухгалтерии
        НаборЗаписей = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
        НаборЗаписей.Отбор.Регистратор.Установить(СсылкаДок);
        НаборЗаписей.Прочитать();
        
        Если НаборЗаписей.Количество() > 0 Тогда
            // Устанавливаем режим Загрузка в Ложь, чтобы платформа 
            // автоматически заполнила пустые значения субконто в СУБД
            НаборЗаписей.ОбменДанными.Загрузка = Ложь;
            Попытка
                НаборЗаписей.Записать();
            Исключение
                ЗаписьЖурналаРегистрации("ОбменДанными.ИсправлениеСубконто",
                    УровеньЖурналаРегистрации.Ошибка,
                    ,
                    СсылкаДок,
                    ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
            КонецПопытки;
        КонецЕсли;
    КонецЦикла;
КонецЕсли;

При перезаписи набора записей с установленным свойством ОбменДанными.Загрузка = Ложь платформа самостоятельно проанализирует структуру метаданных счетов, найдет все незаполненные субконто и добавит строки по умолчанию во вспомогательную таблицу СУБД. Проблема с NULL будет полностью решена.

Решение 3. Использование типовых инструментов исправления данных (БСП)

Если обмен данными уже был произведен, в базе накопилось огромное количество документов с битыми движениями, а отчеты (ОСВ, Карточка счета) показывают некорректные остатки, не спешите писать сложные групповые обработки по перепроведению документов. В современных конфигурациях, работающих под управлением «1С:Библиотеки стандартных подсистем» (БСП), предусмотрен штатный механизм исправления таких ситуаций.

Рассмотрим, как запустить этот инструмент в пользовательском режиме:

  1. Перейдите в раздел НСИ и администрирование (или Администрирование в зависимости от интерфейса конфигурации).
  2. Откройте пункт меню Обслуживание, далее перейдите в подраздел Корректировка данных.
  3. Найдите ссылку на встроенный помощник «Корректировка незаполненных субконто в проводках».
  4. Запустите проверку. Помощник выполнит прямой SQL-запрос к базе данных, выявит проводки, в которых отсутствует физическая связь с таблицей значений субконто (где значение равно NULL), и автоматически создаст для них пустые записи-заглушки.

Преимущество этого метода заключается в том, что исправление происходит быстро, точечно и не требует монопольного режима работы пользователей, а также не приводит к изменению дат и авторов документов-регистраторов.

Подводя итог, отметим, что для предотвращения проблемы в будущем наиболее надежным является Решение 2 с использованием отложенной перезаписи наборов движений. Оно гарантирует, что даже при изменении структуры метаданных (например, при добавлении новых субконто на счета в базе-приемнике) движения загруженных документов автоматически приведутся к правильному виду.

← На главную