В процессе администрирования и сопровождения баз данных на платформе 1С:Предприятие 7.7 специалисты иногда сталкиваются с крайне неприятной аномалией: документ, который визуально помечен на удаление (перечеркнут крестиком в журнале), продолжает делать движения по регистрам оперативного учета или формировать бухгалтерские проводки. В результате этого искажаются отчеты, разъезжаются остатки на складах и взаиморасчеты с контрагентами.
В этой статье мы подробно разберем, почему возникает подобная рассинхронизация на физическом уровне базы данных, проанализируем основные причины сбоя для SQL- и DBF-версий, а также рассмотрим пошаговые инструкции и примеры программного кода для автоматического исправления таких ошибок.
Чтобы понять природу этой проблемы, давайте проанализируем, каким образом платформа 1С 7.7 организует хранение информации в СУБД. В отличие от современных версий платформы, где объектная модель жестко контролирует ссылочную целостность, в «семерке» связь между документами и их движениями более хрупкая.
Данные о документах и их движениях физически разделены по разным таблицам:
_1SJOURN (для SQL-версий) или в файле 1SJOURN.DBF (для файловых версий). За статус проведения отвечает колонка CLOSED, а за пометку на удаление — колонка ISMARK.RA (например, RA325, где число — это внутренний идентификатор регистра в метаданных)._1SENTRY (или 1SENTRY.DBF).В штатном режиме работы, когда пользователь помечает документ на удаление, платформа 1С 7.7 открывает транзакцию и выполняет комплексное действие: меняет значение флага ISMARK на 1 в таблице журнала и одновременно очищает записи с соответствующим IDDOC (идентификатором документа) во всех подчиненных таблицах движений (RA* и _1SENTRY). Если этот процесс нарушается, возникает рассинхронизация.
Рассмотрим основные сценарии, при которых транзакция очистки движений может завершиться некорректно или вообще не запуститься.
1. Аварийное завершение работы в момент транзакции
Если в процессе отмены проведения или пометки документа на удаление на компьютере пользователя происходит критический сбой (например, аварийно закрывается процесс 1cv7s.exe, отключается электропитание, зависает сессия на терминальном сервере или пропадает сетевое соединение с SQL-сервером), транзакция может записаться частично. База данных успевает зафиксировать статус пометки удаления в таблице журнала, но соединение разрывается до того, как СУБД успевает физически удалить строки из таблиц движений.
2. Нарушение целостности индексов в DBF-базах
В файловых версиях баз данных транзакционность поддерживается на программном уровне самой платформы. Если база аварийно завершила работу, индексные файлы (с расширением .CDX) могут потерять синхронизацию с физическими файлами таблиц (.DBF). При повреждении индексов платформа при чтении журнала может считывать одну информацию, а при обращении к регистрам — физически находить записи движений, которые должны были быть удалены.
3. Прямое манипулирование данными (Direct SQL или DBF-редакторы)
Очень часто программисты используют прямые запросы к базе данных через внешние компоненты (например, 1С++) или сторонний софт для ускорения групповых операций (например, при свертке информационной базы). Если разработчик написал запрос обновления статуса в таблице _1SJOURN напрямую:
UPDATE _1SJOURN SET ISMARK = 1, CLOSED = 0 WHERE IDDOC = ' 1Y7 ';
Но при этом забыл написать сопутствующие запросы на удаление движений из всех таблиц регистров RA*, документ визуально станет помеченным на удаление, но фактически продолжит влиять на остатки.
4. Ошибки при обмене данными через УРБД
При использовании распределенных информационных баз (УРБД) изменения мигрируют между периферийными базами и центром. Если в правилах миграции допущены логические ошибки или во время обмена произошел сбой чтения XML/ID-файла переноса, документ может получить статус «Помечен на удаление» в одной из баз, но пакет с удалением его движений не будет применен.
5. Отключение свойства «Автоматическое удаление движений»
В свойствах конфигурации каждого документа есть флаг «Автоматическое удаление движений». Если эта галочка снята, то вся ответственность за очистку регистров ложится на плечи разработчика. В этом случае в модуле документа должна быть прописана процедура ручной очистки. Если в коде перед очисткой движений стоит жесткий оператор Возврат или возникает необработанное исключение, то документ изменит статус, но его движения останутся нетронутыми.
Давайте разберем, как написать простую и эффективную обработку на встроенном языке 1С 7.7, которая позволит обойти всю базу данных и выявить документы, помеченные на удаление, но имеющие физические движения по какому-либо регистру.
Для примера рассмотрим поиск зависших движений по регистру оперативного учета ОстаткиТоваров:
Процедура НайтиОшибкиРегистра()
Док = СоздатьОбъект("Документ");
Рег = СоздатьОбъект("Регистр.ОстаткиТоваров");
// Выбираем все документы в базе данных
Док.ВыбратьДокументы();
Пока Док.ПолучитьДокумент() = 1 Цикл
// Проверяем, установлен ли флаг пометки удаления
Если Док.ПометкаУдаления() = 1 Тогда
// Проверяем, есть ли движения по нашему регистру для этого документа
Рег.ВыбратьДвиженияДокумента(Док.ТекущийДокумент());
Если Рег.ПолучитьДвижение() = 1 Тогда
Сообщить("Найдена ошибка! Документ " + Док.ТекущийДокумент() + " (" + Док.Вид() + ") помечен на удаление, но сохранил движения!");
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Этот простой алгоритм поможет нам локализовать масштаб проблемы и понять, какие именно виды документов пострадали в результате сбоя.
Проанализируем методы исправления этой ситуации. В зависимости от масштаба базы и причин возникновения сбоя, мы можем применить несколько подходов.
Это самый надежный и штатный способ исправления логической целостности базы данных. Перед выполнением процедуры обязательно сделайте резервную копию базы данных!
В процессе логической проверки платформа самостоятельно сопоставит таблицы заголовков документов с таблицами движений и удалит все «осиротевшие» записи из регистров.
Если повреждения носят локальный характер, мы можем программно заставить платформу корректно перезаписать статус документа. При вызове штатных методов интерактивной пометки удаления 1С 7.7 автоматически инициирует правильную транзакцию и очищает регистры.
Напишем небольшую обработку, которая автоматически снимет пометку удаления и установит ее заново для всех некорректных документов:
Процедура ИсправитьДокументы()
Док = СоздатьОбъект("Документ");
Рег = СоздатьОбъект("Регистр.ОстаткиТоваров"); // Укажите ваш проблемный регистр
Док.ВыбратьДокументы();
Пока Док.ПолучитьДокумент() = 1 Цикл
Если Док.ПометкаУдаления() = 1 Тогда
Рег.ВыбратьДвиженияДокумента(Док.ТекущийДокумент());
Если Рег.ПолучитьДвижение() = 1 Тогда
Сообщить("Исправляем документ: " + Док.ТекущийДокумент());
// Открываем транзакцию для безопасности
НачатьТранзакцию();
// Снимаем пометку удаления (документ временно становится просто записанным)
Док.СнятьПометкуУдаления();
// Повторно устанавливаем пометку удаления.
// Этот метод заставит платформу принудительно очистить таблицы движений.
Док.УстановитьПометкуУдаления();
ЗафиксироватьТранзакцию();
КонецЕсли;
КонецЕсли;
КонецЦикла;
Сообщить("Процесс исправления успешно завершен!");
КонецПроцедуры
Важное примечание: Использование транзакции (НачатьТранзакцию() и ЗафиксироватьТранзакцию()) гарантирует, что если в процессе изменения одного из документов произойдет непредвиденная блокировка или сбой, система откатит изменения к исходному состоянию, предотвратив еще большую рассинхронизацию.
Если ваша база работает под управлением MS SQL Server и объем данных настолько велик, что штатное тестирование и исправление занимает слишком много времени, администратор базы данных может выполнить очистку напрямую через SQL Server Management Studio (SSMS).
Перед выполнением этого шага необходимо сопоставить идентификаторы метаданных из файла 1cv7.dd с физическими именами таблиц в SQL. Предположим, что таблица регистра остатков называется _1SENTRY (для проводок) или RA325 (для регистра).
Для очистки зависших бухгалтерских проводок по документам, помеченным на удаление, мы можем использовать следующий SQL-запрос:
-- Удаляем проводки из таблицы _1SENTRY, если документ в журнале _1SJOURN помечен на удаление
DELETE FROM _1SENTRY
WHERE IDDOC IN (
SELECT IDDOC
FROM _1SJOURN
WHERE ISMARK = 1
);
Аналогичным образом мы можем поступить с движениями конкретного регистра накопления:
-- Удаляем движения регистра RA325 по помеченным на удаление документам
DELETE FROM RA325
WHERE IDDOC IN (
SELECT IDDOC
FROM _1SJOURN
WHERE ISMARK = 1
);
После выполнения таких SQL-запросов в обязательном порядке необходимо запустить конфигуратор 1С и выполнить процедуру «Пересчет итогов», чтобы СУБД пересчитала актуальные остатки в таблицах итогов (таблицы с префиксом RG*), иначе остатки в отчетах по-прежнему будут неверными.
Чтобы минимизировать риски повторного появления документов-призраков с активными движениями, рекомендуем придерживаться следующих правил администрирования:
Возврат) до момента очистки старых движений регистра.Мы подробно проанализировали причины сбоя, структуру хранения данных в 1С 7.7 и рассмотрели практические варианты решения проблемы. Применяя данные методики, вы сможете быстро вернуть базу данных в консистентное состояние и обеспечить точность ведения учета.