В практике сопровождения баз 1С периодически возникает ситуация, когда в отчетах (например, в оборотно-сальдовой ведомости) или в результатах запроса к виртуальной таблице остатков регистра бухгалтерии появляется «зависшее» сальдо. При этом одно из субконто принимает значение NULL, а второе — Неопределено или пустое значение. Попытки закрыть такой остаток ручной операцией не приводят к успеху, так как интерактивно подставить NULL в аналитику проводки невозможно. Разберем архитектурные причины этой ошибки и пошаговые методы ее исправления.
Посмотрим на пример запроса к виртуальной таблице остатков, который выявляет наличие подобной проблемы:
ВЫБРАТЬ
ТиповойОстатки.Субконто1 КАК Субконто1,
ТиповойОстатки.Субконто2 КАК Субконто2,
ТИПЗНАЧЕНИЯ(ТиповойОстатки.Субконто1) КАК ТипСубконто1,
ТИПЗНАЧЕНИЯ(ТиповойОстатки.Субконто2) КАК ТипСубконто2,
ТиповойОстатки.Организация КАК Организация,
ТиповойОстатки.СуммаОстаток КАК СуммаОстаток
ИЗ
РегистрБухгалтерии.Типовой.Остатки(&КонецПериода, Счет = &Счет, &МассивСубконто, ) КАК ТиповойОстатки
Для понимания природы ошибки проанализируем устройство хранения данных регистра бухгалтерии в платформе 1С. Данные проводок и аналитики распределены по разным физическим таблицам СУБД: основной таблице движений и отдельной таблице значений субконто. Когда мы обращаемся к виртуальной таблице Остатки, платформа выполняет левое соединение (LEFT JOIN) основной таблицы с таблицей субконто.
Разберем различия между типами пустых значений:
NULL.Выделим основные сценарии, приводящие к отсутствию строк в таблице субконто:
ОбменДанными.Загрузка = Истина типовые механизмы платформы по автозаполнению пустых видов субконто отключаются.Выясним, почему стандартные сервисные функции не устраняют данное сальдо. Процедура «Тестирование и исправление» (включая реструктуризацию и пересчет итогов) строит агрегатные таблицы на основе фактически присутствующих строк в таблицах движений. Отсутствие строки аналитики с точки зрения СУБД не нарушает ссылочную целостность (нет «битых» ссылок), поэтому платформа просто переносит NULL в таблицы итогов. Интерактивная «Операция (бухгалтерский и налоговый учет)» также бессильна: платформа принудительно преобразует пустое поле ввода в пустую ссылку или Неопределено, из-за чего ручная проводка не схлопывает строку с NULL.
Если отчетный период открыт для редактирования, наиболее простым решением является поиск документов-регистраторов, сформировавших некорректные движения, и их перепроведение.
Разберем последовательность действий:
ВЫБРАТЬ
Движения.Регистратор КАК Регистратор,
Движения.Период КАК Период,
Движения.НомерСтроки КАК НомерСтроки,
Движения.СчетДт КАК СчетДт,
Движения.СчетКт КАК СчетКт,
Движения.СубконтоДт1 КАК СубконтоДт1,
Движения.СубконтоКт1 КАК СубконтоКт1
ИЗ
РегистрБухгалтерии.Типовой КАК Движения
ГДЕ
Движения.Период МЕЖДУ &ДатаНач И &ДатаКон
И (Движения.СчетДт = &Счет ИЛИ Движения.СчетКт = &Счет)
Если документы находятся в закрытом периоде и выполнять повторное проведение нельзя, применим метод программной перезаписи наборов записей регистра бухгалтерии. При записи набора без флага загрузки данных платформа 1С автоматически приводит состав субконто к актуальной структуре счета.
Рассмотрим пример кода для программной корректировки набора записей:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| Движения.Регистратор КАК Регистратор
|ИЗ
| РегистрБухгалтерии.Типовой КАК Движения
|ГДЕ
| (Движения.СчетДт = &Счет ИЛИ Движения.СчетКт = &Счет)
| И Движения.Период МЕЖДУ &ДатаНач И &ДатаКон";
Запрос.УстановитьПараметр("Счет", НужныйСчет);
Запрос.УстановитьПараметр("ДатаНач", НачалоДня(ВыбДатаНач));
Запрос.УстановитьПараметр("ДатаКон", КонецДня(ВыбДатаКон));
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Набор = РегистрыБухгалтерии.Типовой.СоздатьНаборЗаписей();
Набор.Отбор.Регистратор.Установить(Выборка.Регистратор);
Набор.Прочитать();
// Перезаписываем набор без включения режима ОбменДанными.Загрузка
// Платформа автоматически создаст недостающие записи субконто
Попытка
Набор.Записать();
Исключение
Сообщить("Ошибка записи движений по документу: " + Строка(Выборка.Регистратор));
КонецПопытки;
КонецЦикла;
В ситуациях, когда на счете требуется явно инициализировать конкретное значение субконто вместо пустой ссылки по умолчанию, обратимся к обходу строк набора записей.
Посмотрим на пример заполнения конкретного вида субконто:
Набор = РегистрыБухгалтерии.Типовой.СоздатьНаборЗаписей();
Набор.Отбор.Регистратор.Установить(ПроблемныйДокумент);
Набор.Прочитать();
Для Каждого Проводка Из Набор Цикл
Если Проводка.СчетДт = ПроблемныйСчет Тогда
// Проверяем и инициализируем субконто нужным значением
Проводка.СубконтоДт[ПланыВидовХарактеристик.ВидыСубконтоТиповые.СтатьиЗатрат] = НужнаяСтатья;
КонецЕсли;
Если Проводка.СчетКт = ПроблемныйСчет Тогда
Проводка.СубконтоКт[ПланыВидовХарактеристик.ВидыСубконтоТиповые.СтатьиЗатрат] = НужнаяСтатья;
КонецЕсли;
КонецЦикла;
Набор.Записать();
После выполнения перезаписи наборов записей или перепроведения документов обязательно выполним контрольный запрос к виртуальной таблице Остатки. Значения NULL исчезнут, а аналитика схлопнется в корректное сальдо.