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

06.04.26

Задачи пользователя - Адаптация типовых решений

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

Вступление 


Представьте себе стандартную картину: конец отчетного периода. Бухгалтер закрывает год, переносит обороты, сверяет остатки. Всё идет по плану… И вдруг — ошибка. Документ, который был проведен месяц назад и не вызывал нареканий, при попытке закрытия месяца или перепроведении выдает фатальное сообщение: «Не заполнены паспортные данные контрагента», «Не указана ставка НДС» или что-то подобное.

Но ведь документ уже был проведен! И он уже сформировал движения в регистрах. Почему же теперь, когда ничего не менялось, система вдруг начала считать его некорректным?

Знакомая ситуация? Если да — вы столкнулись с классическим противоречием между жесткостью бизнес-логики и динамикой реальной базы данных.

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

  1. В логику проведения документа добавили новую проверку. Например, потребовали обязательное наличие ИНН у контрагента. Старые документы, проведенные до этого требования, при перепроведении начинают «падать», хотя их движения абсолютно корректны и менять их не нужно.

  2. Изменились данные в связанных объектах. Скажем, у контрагента удалили паспортные данные (по ошибке или в рамках обновления). Документ от этого не перестал быть правдивым — он просто «ссылается» на уже несуществующий реквизит, но движения его по-прежнему верны.

Результат один: ранее корректная работа системы превращается в головную боль. Бухгалтер не может закрыть месяц, программист срочно пишет обходные обработки, а бизнес теряет время и нервы. И всё это — в самый напряженный момент отчетного периода.

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

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


Проверка на отличия созданных движений и уже сделанных  


В подобной ситуации, если проверка все-таки нужна, но документ был проведен ранее, чем добавлена эта проверка, либо документ проведен, но данные в другом объекте поменяли. Можно проверять движения созданные документом в настоящий момент и движения, которые уже записаны в регистры. И если движения не различаются, пропускать проверку.

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

//Определяет одинаковое ли движение совершает документ с уже записанными регистрами
Функция ОдинаковоеДвижение(Ссылка) Экспорт 
	
	Движения = Ссылка.Движения;
	
	ТаблицыСовпадают = Истина;
	
	КоллекцияДляПоискаРегистра = КоллекцияРегистров();
	
	Для каждого Движение Из Движения Цикл
		
		ПроверяемыйОбъектХЗ = Движение.Выгрузить();  
		КопияДвижения = ПроверяемыйОбъектХЗ.Скопировать();
		КопияДвижения.Очистить(); 
		
		ВыборкаЗаписей = ЗаписиРегистра(Ссылка, Тип(Движение), КоллекцияДляПоискаРегистра); 
		
		Пока ВыборкаЗаписей.Следующий() Цикл
			
			СтрокаДвижений = КопияДвижения.Добавить();
			
			ЗаполнитьЗначенияСвойств(СтрокаДвижений, ВыборкаЗаписей);
			
		КонецЦикла;
		
		ПроверяемыйОбъект = ПроверяемыйОбъектХЗ.Скопировать();
		
		Если НЕ ОдинаковыеТаблицы(ПроверяемыйОбъект, КопияДвижения) Тогда
			
			ТаблицыСовпадают = Ложь;
			
		КонецЕсли;
		
	КонецЦикла; 
	
	Возврат ТаблицыСовпадают
	
КонецФункции // ()

Функция должна срабатывать когда документ уже сформировал свои движения и готовится к записать свои данные в базу данных.

Разберем подробнее это решение.

Первой строкой мы получаем сформированные движения документа:

 Движения = Ссылка.Движения;

Далее ставим флаг по умолчанию, что таблицы совпадают, и получаем коллекцию регистров из метаданных, сопоставляем ее с экземплярами объектов, чтобы получать данные.

Выглядит коллекция регистров примерно так:

//Возвращает регистры из метаданных с сопоставлением регистров объектов
Функция КоллекцияРегистров()
	
	СоответствиеРегистровИМетаданных = Новый Соответствие;
	
	Для каждого РегистрБухгалтерииМетаданных Из Метаданные.РегистрыБухгалтерии Цикл
		
		СоответствиеРегистровИМетаданных.Вставить(РегистрБухгалтерииМетаданных, РегистрыБухгалтерии[РегистрБухгалтерииМетаданных.Имя]); 
		
	КонецЦикла; 
	
	Для каждого РегистрСведенийМетаданных Из Метаданные.РегистрыСведений Цикл
		
		СоответствиеРегистровИМетаданных.Вставить(РегистрСведенийМетаданных, РегистрыСведений[РегистрСведенийМетаданных.Имя]); 
		
	КонецЦикла; 
	
	Для каждого РегистрНакопленияМетаданных Из Метаданные.РегистрыНакопления Цикл
		
		СоответствиеРегистровИМетаданных.Вставить(РегистрНакопленияМетаданных, РегистрыНакопления[РегистрНакопленияМетаданных.Имя]); 
		
	КонецЦикла; 
	
	Для каждого РегистрРасчетаМетаданных Из Метаданные.РегистрыРасчета Цикл
		
		СоответствиеРегистровИМетаданных.Вставить(РегистрРасчетаМетаданных, РегистрыРасчета[РегистрРасчетаМетаданных.Имя]); 
		
	КонецЦикла; 
	
	Возврат СоответствиеРегистровИМетаданных
КонецФункции // ()

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

Далее строим цикл по таблицам регистров, по которым документ совершил движение.

	Для каждого Движение Из Движения Цикл
		
		ПроверяемыйОбъектХЗ = Движение.Выгрузить();  
		КопияДвижения = ПроверяемыйОбъектХЗ.Скопировать();
		КопияДвижения.Очистить(); 
		
		ВыборкаЗаписей = ЗаписиРегистра(Ссылка, Тип(Движение), КоллекцияДляПоискаРегистра); 
		
		Пока ВыборкаЗаписей.Следующий() Цикл
			
			СтрокаДвижений = КопияДвижения.Добавить();
			
			ЗаполнитьЗначенияСвойств(СтрокаДвижений, ВыборкаЗаписей);
			
		КонецЦикла;
		
		ПроверяемыйОбъект = ПроверяемыйОбъектХЗ.Скопировать();
		
		Если НЕ ОдинаковыеТаблицы(ПроверяемыйОбъект, КопияДвижения) Тогда
			
			ТаблицыСовпадают = Ложь;
			
		КонецЕсли;
		
	КонецЦикла; 

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

Далее в переменной ВыборкаЗаписей получаем записи по одному из движений документа из регистра в базе данных.

ВыборкаЗаписей = ЗаписиРегистра(Ссылка, Тип(Движение), КоллекцияДляПоискаРегистра); 

Внутри этой функции мы получаем метаданные регистра по переданному движению документа с помощью функции НайтиПоТипу(). Далее из коллекции сопоставлений регистров и их экземпляров ищем экземпляр регистра и получаем выборку данных по ссылке документа(Регистратору).

Далее сама функция получения записей регистра:

Функция ЗаписиРегистра(Регистратор, Движение, КоллекцияДляПоискаРегистра)
	
	СвойстваРегистра = Метаданные.НайтиПоТипу(Движение);
	
	РегистрДляПоиска = КоллекцияДляПоискаРегистра[СвойстваРегистра];
	
	Возврат РегистрДляПоиска.ВыбратьПоРегистратору(Регистратор); 
	
КонецФункции 

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

		Пока ВыборкаЗаписей.Следующий() Цикл
			
			СтрокаДвижений = КопияДвижения.Добавить();
			
			ЗаполнитьЗначенияСвойств(СтрокаДвижений, ВыборкаЗаписей);
			
		КонецЦикла;
		
		ПроверяемыйОбъект = ПроверяемыйОбъектХЗ.Скопировать();
		
		Если НЕ ОдинаковыеТаблицы(ПроверяемыйОбъект, КопияДвижения) Тогда
			
			ТаблицыСовпадают = Ложь;
			
		КонецЕсли;

Для сравнения двух таблиц, да и в целом коллекций можно использовать функцию в библиотеке стандартных подсистем(БСП):

ОбщегоНазначения.КоллекцииИдентичны()

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


Заключение


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

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

Предложенная функция ОдинаковоеДвижение() и вспомогательные механизмы – это пример прагматичного подхода к разработке: не «ужесточать правила ради правил», а учитывать реальный контекст работы системы. Документ, который не меняет движений, не должен становиться препятствием для работы пользователей, даже если формально проверка, добавленная позже, считает его «неправильным».


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


Основные преимущества подхода:

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

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

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

Вступайте в нашу телеграмм-группу Инфостарт

См. также

Адаптация типовых решений 1С:Предприятие 8 1С:Документооборот Россия Платные (руб)

Расширение конфигурации для «1С:Документооборот КОРП», редакция 3.0. позволяет: 1.использовать произвольные табличные части в качестве дополнительных реквизитов к документу; 2 использовать произвольные табличные части в шаблонах в формате docx для автоматического заполнения таблиц.

32330 руб.

29.06.2023    11700    35    15    

41

Печатные формы Адаптация типовых решений Бухгалтер Пользователь 1С:Предприятие 8 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 3.0 1С:Розница 3.0 Платные (руб)

Расширение позволяет вывести в табличном документе факсимиле печати и подписей и/или вывести произвольную картинку из прикреплённых файлов организации для 1С УТ 11.5, КА 2.5, ERP 2.5, УНФ 3, Розница 3. Вывод факсимиле возможен в табличные документы УПД, УКД, Счёт-фактура, ТОРГ-12 и другие. Возможно настроить вывод для любых типовых макетов (Акт сверки, М-15, ТТН), для этого потребуется отредактировать макет и разместить на нём картинки с соответствующими именами, при выводе на печать в размещённые картинки будут выводиться факсимиле из прикреплённых рисунков. Редактирование осуществляется через типовой механизм в пользовательском интерфейсе.

6000 руб.

07.02.2023    12584    116    20    

71

Разработка Инструментарий разработчика Работа с интерфейсом Адаптация типовых решений Нейросети 1C:Бухгалтерия 1C:ERP 1С:ЗУП 1С:КА 1С:УНФ 1С:УТ 1С:Розница 1С:ДО 1С:ERP Управление предприятием 2 Платные (руб)

Разработка "Дизайнер форм 1С" реализована в виде расширения 1С и является универсальным инструментом для разработки прототипа форм с целью демонстраций, технических заданий и т.д. Без участия разработчика с возможностью экспорта в файл внешней обработки и генерации формы используя искусственный интеллект.

36600 руб.

28.08.2025    7440    2    2    

6

Банковские операции Адаптация типовых решений Бухгалтер Пользователь 1С:Предприятие 8 1С:Бухгалтерия 3.0 Россия Бухгалтерский учет Платные (руб)

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

9760 руб.

17.06.2025    3146    9    0    

8

Адаптация типовых решений 1С 8.3 1С:Бухгалтерия 3.0 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 3.0 Беларусь Россия Платные (руб)

Расширение "Дополнительные документы" предназначено для создания дополнительных документов различного назначения, как форм для внесения данных так и печатных форм в расширяемой конфигурации пользовательскими средствами, без работы в конфигураторе и внесения изменений в структуру данных. Тестировалось для "1С:БП", "1С:УНФ","1С:КА"

21859 руб.

29.12.2025    1101    1    8    

2

Логистика, склад и ТМЦ Адаптация типовых решений Пользователь 1С:Предприятие 8 1С:Управление нашей фирмой 1.6 1С:Управление нашей фирмой 3.0 Россия Управленческий учет Платные (руб)

Чтобы не допустить путаницы с обещаниями клиентам и для четкого контроля исполнения заказов мы используем резервирование товаров. Расширение для УНФ, чтобы автоматически отменять старые резервы и не мешалть эффективно продавать.

9150 руб.

02.08.2023    7906    25    5    

41
Для отправки сообщения требуется регистрация/авторизация