Как запретить ввод и проведение более одного документа в день в 1С

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

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

Способ 1. Использование периодического регистра сведений

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

Рассмотрим реализацию по шагам:

  1. Создадим новый РегистрСведений (например, с именем КонтрольДокументовЗаДень).
  2. Установим свойство Периодичность в значение День.
  3. Установим Режим записи — Подчинение регистратору.
  4. В качестве регистратора выберем наш документ.
  5. Добавим в измерения ключевые поля, по которым нужна уникальность (например, Организация или Подразделение).

Как это работает: При проведении документа система пытается записать данные в этот регистр. Поскольку периодичность установлена в «День», платформа 1С на уровне СУБД не позволит создать вторую запись с тем же набором измерений за ту же дату. Если пользователь попытается провести второй документ, система выдаст стандартную ошибку о неуникальности записей в регистре.

Преимущества: Минимум кода, высокая надежность, автоматическая очистка записей при отмене проведения документа.

Недостатки: Сообщение об ошибке выглядит техническим («Запись с такими ключевыми полями уже существует»), что может сбивать с толку обычного пользователя. Также это занимает дополнительное место в базе данных.

Способ 2. Программная проверка в модуле документа

Если нам нужно более гибкое решение и понятные пользователю сообщения, проанализируем вариант с написанием кода в модуле объекта. Мы будем использовать обработчик события ПередЗаписью или ОбработкаПроверкиЗаполнения. Однако наиболее правильно выполнять проверку именно при проведении, чтобы не мешать пользователю сохранять черновики.

Разберем пример кода, который нужно разместить в модуле документа:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
	
	Если ОбменДанными.Загрузка Тогда
		Возврат;
	КонецЕсли;

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

Проанализируем важные детали этого кода:

Способ 3. Подписка на события

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

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

  1. Создадим новый объект ПодпискаНаСобытие в дереве метаданных.
  2. В поле Источник выберем необходимые типы документов.
  3. В поле Событие выберем ПередЗаписью.
  4. В обработчике подписки (общий модуль) напишем универсальный код, который будет анализировать Источник и выполнять запрос к соответствующей таблице метаданных.

Этот метод считается наиболее «элегантным» в современной разработке, так как он позволяет централизованно управлять логикой контроля для всей системы.

Оптимизация интерфейса и UX

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

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

Также рассмотрим возможность использования Функциональных опций. Вы можете вынести этот контроль в настройки программы. Например, создать константу ЗапретитьДублиДокументовВДень. В коде проверки добавим условие: если константа ложна, проверка пропускается. Это позволит администратору системы гибко управлять правилами без помощи программиста.

Нюанс с часовыми поясами

Если ваша информационная база работает в нескольких часовых поясах, определение «начала дня» может вызвать сложности. В таком случае рекомендуется использовать Универсальное время (UTC) или приводить дату документа к времени сеанса сервера. Если для бизнеса «день» — это календарные сутки по московскому времени, используйте функции работы с датами с явным указанием правил смещения времени, чтобы избежать ситуации, когда один документ записан «вчера» по серверу, но «сегодня» по клиенту.

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

← На главную