Каждый практикующий специалист 1С или опытный бухгалтер рано или поздно сталкивается с загадочной ситуацией: в оборотно-сальдовой ведомости (ОСВ) по какому-либо счету (например, по счету 02 «Амортизация основных средств» или 01 «Основные средства») висит непонятная сумма. При этом попытки детализировать эту сумму, открыв карточку счета, не приносят результатов — отчет оказывается абсолютно пустым, либо показывает эту сумму «из ниоткуда» на самую раннюю дату (например, на 1989 год или даже на «начало времен» — 01.01.0001). Стандартные документы-регистраторы отсутствуют, ручные операции не создавались, а база данных ведет себя некорректно, искажая отчетность по налогу на имущество или баланс.
В этой статье мы подробно разберем, почему возникают такие «фантомные» остатки, проанализируем внутреннее устройство регистров бухгалтерии в платформе «1С:Предприятие 8.3», выясним, почему стандартное тестирование и исправление (ТИИ) часто оказывается бессильным, и пошагово решим эту проблему с помощью программных и интерактивных методов.
Для того чтобы понять природу этого сбоя, обратимся к архитектуре СУБД, на которой работает платформа 1С. Любой регистр накопления или регистр бухгалтерии (в нашем случае это основной регистр Хозрасчетный) на уровне базы данных состоит из нескольких физических таблиц:
_AccRg в MS SQL или PostgreSQL). Каждая строка здесь — это физическое действие: проведение документа, ручная операция или корректировка регистров._AccRgT), в которых платформа 1С хранит предварительно рассчитанные и агрегированные остатки и обороты в разрезе месяцев, счетов и субконто. Это необходимо для того, чтобы тяжелые отчеты (ОСВ, баланс) формировались за секунды, а не сканировали терабайты детальных проводок за всю историю ведения учета при каждом запросе.В идеальном состоянии данные в таблице движений и таблице итогов строго синхронизированы. Однако в результате программных сбоев, аварийного завершения работы сервера СУБД, некорректной работы обработок по прямому удалению документов (без контроля итогов) или специфических багов платформы 1С (особенно связанных с механизмом разделения итогов при высокой параллельной работе пользователей) происходит рассинхронизация. В таблице итогов СУБД зависает «осиротевшая» запись с определенной суммой, в то время как в таблице движений никаких проводок на эту сумму не существует. При построении ОСВ система обращается к таблице итогов и выводит эту цифру, но при попытке расшифровать ее (открыть карточку счета) система идет в таблицу движений и ничего там не находит, возвращая пустой отчет.
Прежде чем приступать к исправлению, нам необходимо убедиться, что мы имеем дело именно с рассогласованием итогов, а не с реально существующей, но скрытой проводкой (например, сделанной в «далеком будущем» из-за опечатки в дате документа типа 2358 года). Для этого воспользуемся консолью запросов. Нам нужно сопоставить данные виртуальной таблицы остатков и физической таблицы движений.
Разберем пример запроса, который поможет выявить наличие реальных проводок за сомнительный период:
ВЫБРАТЬ
Хозрасчетный.Регистратор КАК Регистратор,
Хозрасчетный.Период КАК Период,
Хозрасчетный.Сумма КАК Сумма,
Хозрасчетный.СчетДт КАК СчетДт,
Хозрасчетный.СчетКт КАК СчетКт
ИЗ
РегистрБухгалтерии.Хозрасчетный КАК Хозрасчетный
ГДЕ
Хозрасчетный.Период МЕЖДУ &НачалоПериода И &КонецПериода
И (Хозрасчетный.СчетДт = &ЦелевойСчет ИЛИ Хозрасчетный.СчетКт = &ЦелевойСчет)
В качестве параметров укажем:
&НачалоПериода — '0001-01-01' (самая ранняя возможная дата в системе).&КонецПериода — дата, предшествующая началу реального ведения учета (например, '1990-01-01').&ЦелевойСчет — счет, по которому зависла сумма (в нашей ситуации — счет 02.01 или 02).Если в результате выполнения этого запроса выборка оказалась абсолютно пустой, но в ОСВ на эту же дату висит дебетовый или кредитовый остаток, мы имеем дело со стопроцентным нарушением логической целостности итогов СУБД.
Казалось бы, решение очевидно: нужно запустить «Тестирование и исправление» (ТИИ) из конфигуратора с установленным флагом «Пересчет итогов» либо выполнить пересчет через стандартные административные функции. Однако на больших базах данных эта процедура может длиться сутками (вплоть до 3–4 дней) и в итоге все равно завершиться неудачей. Почему так происходит?
Платформа 1С использует оптимизацию хранения данных. Чтобы база данных не раздувалась до невероятных размеров, разработчики платформы ввели механизмы ограничения хранения итогов. У любого регистра бухгалтерии существуют параметры:
По умолчанию в типовой конфигурации «1С:Бухгалтерия 3.0» минимальный период рассчитанных итогов часто сдвинут на дату начала реального ведения учета (например, 01.01.2015). Если «битая» запись в таблице итогов СУБД имеет дату ранее этого минимального периода (например, проецируется на пустую дату 01.01.0001), то при запуске стандартного ТИИ или обычного пересчета итогов платформа просто **игнорирует** этот временной пласт. Она производит расчеты только внутри установленного диапазона. Фантомный остаток, находящийся «за бортом» минимального периода, остается нетронутым и продолжает отравлять жизнь бухгалтерам.
Для того чтобы заставить платформу 1С принудительно очистить и пересчитать абсолютно всю временную шкалу регистра бухгалтерии, нам необходимо сдвинуть минимальный период рассчитанных итогов в «начало времен» — на дату 01.01.0001. После этого платформа принудительно проверит целостность таблиц и сопоставит итоги с реальными проводками, начиная с Рождества Христова.
Выполнить эту операцию можно программно. Напишем простую обработку. Разберем по шагам код, который необходимо выполнить в контексте сервера:
Процедура СброситьМинимальныйПериодИтогов() Экспорт
// Получаем менеджер регистра бухгалтерии "Хозрасчетный"
Регистр = РегистрыБухгалтерии.Хозрасчетный;
// Выведем текущие настройки для анализа в окно сообщений
ТекущийМинимум = Регистр.ПолучитьМинимальныйПериодРассчитанныхИтогов();
ТекущийМаксимум = Регистр.ПолучитьМаксимальныйПериодРассчитанныхИтогов();
Сообщить("Текущий минимальный период итогов: " + СокрЛП(ТекущийМинимум));
Сообщить("Текущий максимальный период итогов: " + СокрЛП(ТекущийМаксимум));
// Устанавливаем минимальный период в самую раннюю возможную дату 1С
Попытка
Регистр.УстановитьМинимальныйПериодРассчитанныхИтогов('00010101');
Сообщить("Минимальный период успешно сброшен на 01.01.0001!");
Исключение
ВызватьИсключение "Не удалось установить минимальный период. Ошибка: " + ОписаниеОшибки();
КонецПопытки;
КонецПроцедуры
Важное предупреждение: так как база данных может быть огромной, выполнение этого кода и последующий пересчет итогов могут занять значительное время и потребовать свободных ресурсов оперативной памяти на сервере приложений 1С и сервере СУБД (MS SQL / PostgreSQL). Настоятельно рекомендуем выполнять эту процедуру на копии базы данных перед тем, как запускать её на рабочей системе!
Если вы не хотите писать код или запускать внешние обработки, в платформе 1С:Предприятие 8.3 предусмотрен интерактивный механизм управления итогами. Рассмотрим, как им воспользоваться:
Хозрасчетный.После того как минимальный период успешно установлен в значение 01.01.0001, нам необходимо запустить пересчет итогов. Для этого у нас есть два пути:
Вариант А: Через режим конфигуратора (рекомендуется для файловых баз)
Вариант Б: Через режим предприятия (рекомендуется для больших клиент-серверных баз)
В окне «Управление итогами» (которое мы открывали на Шаге 4) выделите регистр Хозрасчетный, нажмите правую кнопку мыши и выберите команду «Пересчитать итоги». Платформа произведет перестроение индексных таблиц и физических таблиц итогов на сервере СУБД без необходимости монопольного захвата всей базы данных в конфигураторе.
После завершения этой операции откройте оборотно-сальдовую ведомость по проблемному счету. Вы увидите, что «фантомный» остаток в 3 060,72 руб. (или любая другая зависшая сумма) полностью исчез, так как система перестроила таблицы итогов исключительно на основании реально существующих проводок из таблицы движений.
Если ваша база данных имеет объем в сотни гигабайт или терабайты, полный пересчет итогов с '0001-01-01' может парализовать работу предприятия на длительный срок. В таком случае опытный системный администратор или администратор баз данных (DBA) может решить проблему непосредственно на уровне СУБД. Проанализируем этот сценарий на примере MS SQL Server:
Хозрасчетный. Для этого в 1С можно воспользоваться методом ПолучитьСтруктуруХраненияБазыДанных() или специализированными обработками. Предположим, имя таблицы итогов — _AccRgT1._AccRg1:
SELECT t.*
FROM _AccRgT1 t
LEFT JOIN _AccRg1 d ON t._AccountRRef = d._AccountRRef AND t._Fld123 = d._Fld123 -- пример связи по субконто и счетам
WHERE d._Period IS NULL AND t._FldSumBalance <> 0
Если такие «сиротские» строки обнаружены, их можно аккуратно удалить прямой SQL-командой DELETE. Помните, что любое прямое изменение данных в СУБД в обход платформы 1С нарушает лицензионное соглашение и правила технической поддержки, поэтому всегда делайте резервную копию (бэкап) перед проведением подобных работ!
Чтобы в будущем вам не пришлось сталкиваться с «фантомными» суммами на счетах учета, рекомендуем придерживаться нескольких простых правил:
РегистрБухгалтерииНаборЗаписей) с включенным свойством Записать(Истина), обеспечивающим автоматическое обновление агрегатов и итогов регистра.Проанализировав ситуацию и выполнив пошагово предложенные рекомендации, вы сможете раз и навсегда избавить вашу информационную базу от некорректных остатков прошлых лет, обеспечив абсолютную достоверность регламентированной и налоговой отчетности.