Как исправить фантомные остатки в 1С:Бухгалтерия, которые появляются «из ниоткуда»?

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

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

В этой статье мы подробно разберем, почему транзакции из будущего могут сбивать итоги в прошлом, проанализируем глубинную суть конфликта между значениями NULL, Неопределено и пустой ссылкой в регистрах бухгалтерии, а также рассмотрим пошаговые методы локализации и исправления этой ошибки с помощью консоли запросов и специализированного программного кода.

Описанная проблема является классической для платформы «1С:Предприятие 8» (в частности, для регистра бухгалтерии Хозрасчетный в конфигурации «Бухгалтерия предприятия 3.0») и связана с оптимизацией хранения данных СУБД.

Давайте вместе разберемся в механизмах платформы и выясним, как победить этот системный сбой.

 

Почему транзакция из будущего сбивает итоги в прошлом?

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

Вместо этого в системе задействован механизм хранения рассчитанных физических итогов:

В этот момент и кроется главная опасность. Если в проводке за 31 декабря допущена системная ошибка в аналитике (например, некорректно записано значение субконто или измерения), то при математическом «откате» движений назад алгоритм СУБД ломается. Программа не может корректно сопоставить и вычесть движения, из-за чего на более ранних датах (например, на 2 декабря) возникает фантомный остаток, которого физически никогда не существовало в базе данных.

 

Суть конфликта: NULL, «Неопределено» и «ПустаяСсылка»

В базе данных регистров бухгалтерии 1С эти понятия принципиально различаются на уровне СУБД (будь то Microsoft SQL Server или PostgreSQL). Путаница между ними — главный источник «зависающих» остатков:

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

 

Типичные причины возникновения искажений в базе данных

При обычном интерактивном вводе документов через интерфейс программы платформа 1С строго контролирует типы данных и автоматически подставляет нужные пустые ссылки или NULL в проводки. Однако некорректные записи часто проникают в базу следующими путями:

 

Пошаговое руководство по диагностике и решению проблемы

Если стандартное «Тестирование и исправление» (ТиИ) с флагом «Пересчет итогов» оказывается бессильно, это означает, что ошибка кроется в самих физических записях регистра бухгалтерии, на основе которых строятся итоги. Нам необходимо найти «битую» проводку и исправить ее структуру.

Проанализируем ситуацию по шагам.

Шаг 1: Локализация виновника с помощью консоли запросов

Для поиска проблемной записи обратимся напрямую к реальной (а не виртуальной) таблице регистра бухгалтерии РегистрБухгалтерии.Хозрасчетный по нужному счету. Наша задача — найти строки, где нарушены правила заполнения аналитики.

Откроем консоль запросов и выполним следующий запрос для анализа субконто (например, для проверки наличия Неопределено или нетипизированного NULL там, где должна быть пустая ссылка):


ВЫБРАТЬ
	Хозрасчетный.Период КАК Период,
	Хозрасчетный.Регистратор КАК Регистратор,
	Хозрасчетный.НомерСтроки КАК НомерСтроки,
	Хозрасчетный.СубконтоДт1 КАК СубконтоДт1,
	Хозрасчетный.СубконтоКт1 КАК СубконтоКт1
ИЗ
	РегистрБухгалтерии.Хозрасчетный КАК Хозрасчетный
ГДЕ
	Хозрасчетный.СчетДт = &ПроверяемыйСчет
	И (Хозрасчетный.СубконтоДт1 = НЕОПРЕДЕЛЕНО 
		ИЛИ Хозрасчетный.СубконтоДт1 ЕСТЬ NULL)

Если мы подозреваем проблему с измерениями (например, с измерением Подразделение, по которому на данном счете учет вестись не должен, но туда по ошибке записалась пустая ссылка вместо NULL), выполним следующий запрос:


ВЫБРАТЬ
	Хозрасчетный.Период КАК Период,
	Хозрасчетный.Регистратор КАК Регистратор,
	Хозрасчетный.ПодразделениеДт КАК ПодразделениеДт
ИЗ
	РегистрБухгалтерии.Хозрасчетный КАК Хозрасчетный
ГДЕ
	Хозрасчетный.СчетДт = &ПроверяемыйСчет
	И НЕ Хозрасчетный.ПодразделениеДт ЕСТЬ NULL
	И Хозрасчетный.ПодразделениеДт = ЗНАЧЕНИЕ(Справочник.ПодразделенияОрганизаций.ПустаяСсылка)

Этот запрос покажет нам все документы, которые записали в базу данных пустую ссылку подразделения вместо системного NULL.

 

Шаг 2: Исправление найденных ошибок

В зависимости от состояния информационной базы и возможности изменения документов выберем один из способов исправления.

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

Способ Б: Программное исправление через ОбменДанными
Если период закрыт, сдана отчетность и перепроводить документы категорически нельзя (чтобы не поплыли другие показатели), необходимо исправить движения программно без изменения самого документа. Для этого напишем внешнюю обработку, которая перезапишет только движения регистра бухгалтерии в режиме загрузки данных.

Рассмотрим пример кода для исправления движений документа:


// Выбираем движения конкретного документа-виновника
НаборЗаписей = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(ПроблемныйДокумент);
НаборЗаписей.Прочитать();

Для Каждого Запись Из НаборЗаписей Цикл
	
	// Пример исправления: заменяем пустую ссылку подразделения на NULL, 
	// если по правилам учета подразделение не должно быть заполнено
	Если Запись.СчетДт.УчетПоПодразделениям = Ложь Тогда
		Если Запись.ПодразделениеДт <> Неопределено И ЗначениеЗаполнено(Запись.ПодразделениеДт) = Ложь Тогда
			// Платформа автоматически сбросит значение в NULL при записи набора, 
			// если мы очистим некорректную пустую ссылку
			Запись.ПодразделениеДт = Неопределено; 
		КонецЕсли;
	КонецЕсли;
	
	// Исправление пустых субконто: приводим Неопределено к правильному типу пустой ссылки
	Если Запись.СубконтоДт1 = Неопределено Тогда
		// Предположим, первое субконто должно иметь тип "Контрагенты"
		ТипСубконто = Запись.СчетДт.ВидыСубконто[0].ВидСубконто.ТипЗначения.Типы()[0];
		Запись.СубконтоДт1 = Новый(ТипСубконто);
	КонецЕсли;
	
КонецЦикла;

// Включаем режим загрузки, чтобы обойти проверки и блокировки закрытого периода
НаборЗаписей.ОбменДанными.Загрузка = Истина;
НаборЗаписей.Записать();

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

 

Шаг 3: Полный пересчет итогов

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

Для этого выполним следующие действия:

  1. Перейдем в меню Администрирование — Обслуживание — Регламентные операции — Управление итогами и агрегатами.
  2. В списке выберем регистр бухгалтерии Хозрасчетный.
  3. Установим период расчета итогов по текущий месяц включительно и нажмем кнопку Полный пересчет итогов.
  4. Также можно запустить процедуру через Конфигуратор: меню Администрирование — Тестирование и исправление... — выбрать пункт Пересчет итогов и нажать Выполнить.

После завершения пересчета итогов сформируем оборотно-сальдовую ведомость повторно. Вы увидите, что фантомный остаток, возникавший «из ниоткуда», успешно исчез, а математический расчет сальдо между периодами снова работает корректно и предсказуемо.

← На главную