Как исправить отрицательные остатки в регистре 1С при перепроведении документов задним числом и нужно ли для этого восстанавливать последовательность?

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

При активной работе пользователей в информационных базах 1С часто возникает ситуация, когда документы проводятся или изменяются задним числом. Это неизбежно приводит к нарушению хронологической последовательности учета. Самое распространенное и неприятное следствие этого процесса — появление отрицательных остатков (так называемых «минусов») в регистрах накопления. В этой статье мы подробно разберем, как решить проблему отрицательных остатков в самописной или типовой конфигурации 1С, обязательно ли для этого создавать объект метаданных Последовательность, и как правильно реализовать программные механизмы контроля и перепроведения документов.

Почему возникают отрицательные остатки при работе задним числом?

Представим простую ситуацию: на складе числится 10 единиц товара. Пользователь оформляет расходную накладную на все 10 единиц. Остаток становится равным нулю. Спустя день другой пользователь открывает вчерашний приходный документ и уменьшает количество поступившего товара с 10 до 8 единиц. Если система позволяет провести этот документ без предупреждений, то в момент изменения прихода на складе задним числом образуется остаток 8 единиц. При этом более поздний расходный документ на 10 единиц остается проведенным. В результате в регистре остатков образуется минус 2 единицы.

Для исправления таких ситуаций требуется перепровести цепочку документов в строгой хронологической последовательности, начиная с момента самого первого изменения в прошлом. Программа должна заново пересчитать остатки в каждой точке времени и, если товара в какой-то момент перестанет хватать, заблокировать проведение расходного документа.

Нужен ли стандартный объект метаданных «Последовательность»?

В платформе 1С существует стандартный объект метаданных — Последовательность. Он предназначен для автоматического отслеживания хронологии документов и регистрации документов, нарушивших эту хронологию (сдвиг границы последовательности назад). Однако использовать этот объект в современных реалиях разработки необязательно, а в некоторых случаях даже вредно.

Проанализируем основные недостатки стандартного объекта Последовательность:

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

Критическая ошибка при перепроведении: Дата против Момента времени

Часто начинающие разработчики при написании обработки для перепроведения документов допускают грубую ошибку — они выбирают документы запросом и сортируют их по полю Дата. Рассмотрим, почему так делать категорически нельзя.

В пределах одной секунды в базе данных может быть записано и проведено несколько документов. Если мы отсортируем их просто по дате, СУБД вернет их в случайном порядке. В результате документ расхода может попытаться провериться раньше, чем документ прихода, записанный в ту же секунду. Это приведет к ложному отказу в проведении из-за нехватки остатка.

Для правильного упорядочивания документов в 1С используется специальный объект — МоментВремени. Он состоит из даты (с точностью до секунды) и уникальной ссылки на документ. Платформа гарантирует, что сортировка по моменту времени всегда возвращает документы в строго уникальном и физически правильном хронологическом порядке их записи в базу данных.

Посмотрим на пример правильного запроса для выборки документов на перепроведение:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	РасходнаяНакладная.Ссылка КАК Ссылка
    |ИЗ
    |	Документ.РасходнаяНакладная КАК РасходнаяНакладная
    |ГДЕ
    |	РасходнаяНакладная.Проведен = ИСТИНА
    |	И РасходнаяНакладная.Дата МЕЖДУ &НачалоПериода И &КонецПериода
    |
    |УПОРЯДОЧИТЬ ПО
    |	РасходнаяНакладная.МоментВремени";

Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(ДатаНачала));
Запрос.УстановитьПараметр("КонецПериода", КонецДня(ДатаОкончания));

Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    // Программное перепроведение документа
    ДокументОбъект = Выборка.Ссылка.ПолучитьОбъект();
    Попытка
        ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение, РежимПроведенияДокумента.Неоперативный);
    Исключение
        ЗаписьЖурналаРегистрации("ПерепроведениеДокументов",
            УровеньЖурналаРегистрации.Предупреждение,
            ,
            Выборка.Ссылка,
            "Ошибка проведения документа: " + ОписаниеОшибки());
    КонецПопытки;
КонецЦикла;

Как не допустить появление отрицательных остатков в будущем?

Просто перепровести документы — это временное решение. Чтобы отрицательные остатки не появлялись снова при очередном изменении документов пользователями, необходимо внедрить в код проведения жесткий контроль остатков. В платформе 1С реализованы две основные методики контроля.

Методика 1: «Старый» (классический) метод контроля остатков

Этот метод заключается в том, что перед непосредственной записью движений в регистр программа делает запрос к таблице остатков и проверяет, достаточно ли товара на складе. Если товара хватает, формируются движения расхода.

Разберем алгоритм по шагам:

  1. В процедуре ОбработкаПроведения мы отключаем признак автоматической записи движений документа (свойства Записывать).
  2. Очищаем существующие движения документа в этом регистре, чтобы документ «не проверял сам себя».
  3. Запросом получаем текущие остатки товаров по нужным позициям из табличной части.
  4. Сравниваем требуемое количество с остатком в регистре. Если обнаруживается нехватка, выводим сообщение пользователю и устанавливаем параметр Отказ = Истина.
  5. Если товара хватает, добавляем записи в движения регистра и взводим флаг Движения.ОстаткиТоваров.Записывать = Истина.

Главный недостаток этой методики — необходимость предварительного очищения и записи пустых движений документа, что ведет к избыточному числу обращений к СУБД и накладывает блокировки на таблицы остатков еще до проверки.

Методика 2: «Новый» (рекомендуемый) метод контроля остатков

Этот подход более прогрессивен и оптимизирован для многопользовательской работы. Он минимизирует блокировки и значительно ускоряет проведение документов. Суть метода заключается в том, что документ сначала записывает свои движения по расходу в регистр накопления «не глядя» на текущие остатки, а затем одним запросом проверяет, не ушел ли остаток по измененным товарам в минус.

Рассмотрим пример реализации этой методики в модуле документа:


Процедура ОбработкаПроведения(Отказ, РежимПроведения)
	
	// Очищаем старые движения текущего документа перед проведением
	Движения.ОстаткиНоменклатуры.Записывать = Истина;
	Движения.ОстаткиНоменклатуры.Очистить();
	
	// Сначала записываем новые движения расхода без предварительной проверки
	Для Каждого СтрокаТЧ Из Товары Цикл
		Движение = Движения.ОстаткиНоменклатуры.Добавить();
		Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
		Движение.Период = Дата;
		Движение.Номенклатура = СтрокаТЧ.Номенклатура;
		Движение.Количество = СтрокаТЧ.Количество;
	КонецЦикла;
	
	// Принудительно записываем движения в базу данных
	Движения.Записать();
	
	// Проводим контроль остатков ПОСЛЕ того, как движения записаны в БД
	// Если в результате нашего расхода остаток стал отрицательным, мы отменим транзакцию
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ
		|	Остатки.Номенклатура КАК Номенклатура,
		|	Остатки.Номенклатура.Представление КАК НоменклатураПредставление,
		|	-Остатки.КоличествоОстаток КАК Нехватка
		|ИЗ
		|	РегистрНакопления.ОстаткиНоменклатуры.Остатки(&МоментКонтроля, Номенклатура В
		|		(ВЫБРАТЬ РАЗЛИЧНЫЕ ТЧ.Номенклатура ИЗ Документ.РасходнаяНакладная.Товары КАК ТЧ ГДЕ ТЧ.Ссылка = &Ссылка)) КАК Остатки
		|ГДЕ
		|	Остатки.КоличествоОстаток < 0";
	
	// В качестве границы контроля передаем МоментВремени документа или Границу
	// Для оперативного проведения можно использовать неопределенную границу, 
	// но для проведения задним числом важно контролировать остаток на момент проведения документа.
	ГраницаКонтроля = Новый Граница(МоментВремени(), ГраницаТипа.ВключаяСобытие);
	Запрос.УстановитьПараметр("МоментКонтроля", ГраницаКонтроля);
	Запрос.УстановитьПараметр("Ссылка", Ссылка);
	
	РезультатЗапроса = Запрос.Выполнить();
	Если Не РезультатЗапроса.Пустой() Тогда
		Отказ = Истина;
		ВыборкаОшибок = РезультатЗапроса.Выбрать();
		Пока ВыборкаОшибок.Следующий() Цикл
			Сообщение = Новый СообщениеПользователю;
			Сообщение.Текст = СтрШаблон("Недостаточно товара %1 в количестве %2 единиц!", 
				ВыборкаОшибок.НоменклатураПредставление, 
				ВыборкаОшибок.Нехватка);
			Сообщение.Сообщить();
		КонецЦикла;
	КонецЕсли;

КонецПроцедуры

Полезные практические приемы управления хронологией

Для того чтобы облегчить жизнь пользователям и минимизировать возникновение коллизий при проведении документов день в день, рекомендуем внедрить следующие организационно-технические приемы:

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

← На главную