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