В практике администраторов и программистов 1С периодически возникает ситуация, когда из-за невнимательности пользователя или временного снятия даты запрета редактирования в систему попадает документ с некорректной датой, например, 0201 год или даже 0001 год. Последствия такой ошибки могут быть катастрофическими для регламентных операций: система начинает требовать закрытие месяца за все прошедшие две тысячи лет. Даже если сам документ найден и исправлен, «шлейф» в технических регистрах часто остается, мешая нормальной работе. Рассмотрим подробно, как диагностировать, найти и полностью устранить последствия ввода таких «древних» документов.
Прежде всего, разберем, почему система «сходит с ума». В современных конфигурациях на базе 1С:ERP, 1С:Комплексная автоматизация или 1С:Управление торговлей 11 механизмы закрытия месяца работают по принципу цепочки. Если в каком-то периоде (пусть даже это II век нашей эры) произошло движение по регистрам, система фиксирует необходимость пересчета себестоимости и распределения затрат начиная с этого момента и до текущего дня.
Проблема усугубляется тем, что простое удаление записи в регистре сведений Задания к закрытию месяца часто не помогает. Вы можете столкнуться с «эффектом домино»: удаляя строку за 300-й год, вы обнаруживаете, что система тут же генерирует новую строку за 301-й. Это происходит из-за того, что алгоритмы проверки актуальности данных видят незакрытый «хвост» в прошлом и пытаются восстановить последовательность расчетов.
Если визуально в журналах документов ошибка не видна (например, документ был помечен на удаление, но не удален, или его движения остались в базе), необходимо воспользоваться программными методами поиска. Проанализируем ситуацию и составим запрос ко всем документам системы.
Самый эффективный способ — перебор метаданных. Рассмотрим пример кода, который поможет найти все документы, дата которых меньше разумного предела (например, ранее 2000 года), исключая при этом пустые даты:
// Пример обхода метаданных для поиска ошибочных дат
Для Каждого МетаДокумент Из Метаданные.Документы Цикл
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Т.Ссылка КАК Ссылка,
| Т.Дата КАК Дата
|ИЗ
| Документ." + МетаДокумент.Имя + " КАК Т
|ГДЕ
| Т.Дата < &МинимальнаяДата
| И Т.Дата <> ДАТАВРЕМЯ(1, 1, 1)";
Запрос.УстановитьПараметр("МинимальнаяДата", '20000101');
Результат = Запрос.Выполнить();
Если Не Результат.Пустой() Тогда
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить("Найден документ: " + Выборка.Ссылка + " с датой " + Выборка.Дата);
КонецЦикла;
КонецЕсли;
КонецЦикла;
Важный момент: при написании запроса обязательно используйте условие Т.Дата <> ДАТАВРЕМЯ(1, 1, 1). В 1С пустая дата считается как 01.01.0001, и если её не исключить, вы получите тысячи ложных срабатываний по всем документам, которые еще не были записаны или имеют пустые реквизиты дат в дополнительных полях.
Разберем, почему 1С вообще позволяет записывать такие даты. Это связано с механизмом работы с Microsoft SQL Server. В SQL тип данных datetime не поддерживает даты ранее 1753 года. Чтобы обойти это ограничение, 1С при создании базы на SQL-сервере предлагает параметр «Смещение дат» (обычно 2000 лет).
Если смещение установлено в 2000, то дата 0001 год в 1С физически хранится в таблицах SQL как 2001 год. Это позволяет записывать любые исторические даты, но именно это и становится ловушкой: для SQL сервера дата 0201 год (хранимая как 2201) является абсолютно валидной, и сервер не выдает ошибку при записи, «пропуская» опечатку пользователя в базу.
После того как документ найден и исправлен (ему установлена корректная дата и он перепроведен), необходимо вычистить технические регистры, иначе закрытие месяца продолжит требовать расчет за 2000 лет. Выясним причину, по которой записи не исчезают сами: система хранит записи о необходимости расчета в специальных регистрах сведений.
Проанализируем список регистров, которые нужно проверить и очистить от записей с древними датами:
Задания к расчету себестоимостиЗадания к распределению расчетов с клиентамиЗадания к распределению расчетов с поставщикамиОчередь заданий (в некоторых случаях)Задания к закрытию месяцаДля очистки лучше всего использовать обработку, которая записывает пустой набор записей по конкретному периоду. Рассмотрим пример логики очистки:
// Очистка регистра сведений "Задания к расчету себестоимости" за некорректный период
Набор = РегистрыСведений.ЗаданияКРасчетуСебестоимости.СоздатьНаборЗаписей();
Набор.Отбор.Период.Установить('02010101', '02011231'); // Указываем проблемный диапазон
Набор.Записать();
Если после очистки записи появляются снова, это означает, что где-то в базе остались движения (записи в регистрах накопления) с некорректной датой. В этом случае нужно искать записи в регистрах Выручка и себестоимость продаж или Движения Номенклатура - Номенклатура, где поле Период содержит «древнюю» дату.
Чтобы в будущем пользователи не могли ввести некорректную дату даже при снятой дате запрета, рекомендуется настроить «Год начала рабочего столетия». В параметрах системы (Сервис — Параметры) этот параметр определяет, как 1С интерпретирует ввод двух цифр года. Например, если указать 1920 год, то при вводе «23» система поймет это как 2023, а не 1923 или 0023.
Однако более надежным методом является внедрение небольшого расширения. Разберем шаги:
ПередЗаписью для всех документов.Пример кода в подписке на событие:
Процедура ПроверкаДатыПередЗаписью(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт
Если Источник.Дата < '19000101' И ЗначениеЗаполнено(Источник.Дата) Тогда
Сообщить("Вы ввели слишком раннюю дату! Пожалуйста, проверьте год.");
Отказ = Истина;
КонецЕсли;
КонецПроцедуры
Такой подход гарантированно защитит базу от «путешественников во времени» и избавит бухгалтерию от необходимости пересчитывать себестоимость за последние два тысячелетия.