Как настроить автоматическое присвоение номера и даты договорам с клиентами в 1С:Управление торговлей 11.4?

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

В отличие от конфигурации «1С:Бухгалтерия предприятия», где механизм автонумерации договоров доступен из коробки, в конфигурации «1С:Управление торговлей 11.4» (а также в 1С:ERP и 1С:Комплексная автоматизация) разработчики оставили заполнение номера и даты договоров на усмотрение пользователя. Договоры в этой программе являются элементами справочника ДоговорыКонтрагентов, и их бизнес-реквизиты Номер и Дата по умолчанию заполняются вручную. Разберем подробно, как решить эту задачу с помощью доработки конфигурации или создания расширения.

Почему стандартный механизм автонумерации не работает для договоров?

В платформе «1С:Предприятие 8» встроенный механизм автоматического назначения номеров отлично работает для документов. Для справочников также существует автоматическая генерация, но она привязана к стандартному реквизиту Код. В справочнике ДоговорыКонтрагентов для хранения номера договора используется отдельный текстовый реквизит Номер (или НомерДоговора в некоторых версиях), а для даты — реквизит Дата (или ДатаДоговора соответственно). Стандартная платформа не умеет автоматически инкрементировать пользовательские текстовые поля без написания кода.


Где правильно разместить код автонумерации?

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

  1. Проблема одновременной работы: Если два пользователя одновременно откроют форму создания нового договора, система попытается выдать им один и тот же следующий номер. Тот, кто запишет договор вторым, получит ошибку или запишет дублирующийся номер.
  2. Программное создание объектов: Если договоры будут создаваться программно (например, при загрузке с сайта, через API или из внешней CRM-системы), код в форме элемента просто не выполнится, и договоры останутся без номеров.

Правильное решение: Размещать алгоритм генерации номера и заполнения даты необходимо в предопределенной процедуре ПередЗаписью модуля объекта справочника ДоговорыКонтрагентов (или аналогичного метода в расширении конфигурации).


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

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

Рассмотрим пример кода, который необходимо добавить в модуль объекта справочника ДоговорыКонтрагентов в процедуру ПередЗаписью:


Процедура ПередЗаписью(Отказ, Замещение)
	
	// Проверяем, что это новый элемент справочника
	Если ЭтоНовый() Тогда
		
		// Автоматически заполняем дату текущим числом, если она пустая
		Если Не ЗначениеЗаполнено(Дата) Тогда
			Дата = ТекущаяДата();
		КонецЕсли;
		
		// Устанавливаем признак необходимости генерации кода платформой
		// После генерации кода присваиваем его в реквизит Номер
		ЭтотОбъект.УстановитьНовыйКод();
		ЭтотОбъект.Номер = СокрЛП(ЭтотОбъект.Код);
		
	КонецЕсли;
	
КонецПроцедуры

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


Способ №2. Программное вычисление последнего номера через запрос

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

Выясним причину, почему нельзя просто использовать функцию МАКСИМУМ(Номер) в запросе по текстовому полю. В базах данных текстовые строки сортируются посимвольно. Это означает, что строка "9" при сортировке будет считаться больше, чем строка "10" или "100". Чтобы обойти это ограничение, мы должны принудительно приводить номера к фиксированной длине с ведущими нулями (например, "00000001", "00000002") либо преобразовывать строку в число в коде.

Разберем по шагам безопасный алгоритм генерации числового номера в модуле объекта:


Процедура ПередЗаписью(Отказ, Замещение)
	
	Если ЭтоНовый() Тогда
		
		// 1. Установка даты по умолчанию
		Если Не ЗначениеЗаполнено(Дата) Тогда
			Дата = ТекущаяДата();
		КонецЕсли;
		
		// 2. Получение максимального номера из базы данных за текущий год
		Запрос = Новый Запрос;
		Запрос.Текст = 
			"ВЫБРАТЬ
			|	Договоры.Номер КАК Номер
			|ИЗ
			|	Справочник.ДоговорыКонтрагентов КАК Договоры
			|ГДЕ
			|	Договоры.Дата МЕЖДУ &НачалоГода И &КонецГода
			|	И Договоры.ПометкаУдаления = ЛОЖЬ";
		
		Запрос.УстановитьПараметр("НачалоГода", НачалоГода(Дата));
		Запрос.УстановитьПараметр("КонецГода", КонецГода(Date));
		
		РезультатЗапроса = Запрос.Выполнить();
		
		МаксимальныйНомер = 0;
		
		Если Не РезультатЗапроса.Пустой() Тогда
			Выборка = РезультатЗапроса.Выбрать();
			Пока Выборка.Следующий() Цикл
				// Пытаемся преобразовать текстовый номер в число для точного сравнения
				Попытка
					ЧислоНомера = Число(СокрЛП(Выборка.Номер));
					Если ЧислоНомера > МаксимальныйНомер Тогда
						МаксимальныйНомер = ЧислоНомера;
					КонецЕсли;
				Исключение
					// Если номер содержит буквы или символы, игнорируем его при поиске максимального числа
					Продолжить;
				КонецПопытки;
			КонецЦикла;
		КонецЕсли;
		
		// 3. Увеличиваем номер на единицу
		НовыйЧисловойНомер = МаксимальныйНомер + 1;
		
		// 4. Форматируем номер с ведущими нулями для красивого отображения (например, "00001")
		ЭтотОбъект.Номер = Формат(НовыйЧисловойНомер, "ЧЦ=5; ЧДЦ=0; ЧГ=0");
		
	КонецЕсли;
	
КонецПроцедуры

Обратите внимание на то, что в данном запросе мы ограничили выборку рамками текущего года с помощью параметров НачалоГода и КонецГода. Это позволяет начать нумерацию заново с наступлением нового календарного года, что соответствует правилам ведения делопроизводства на большинстве предприятий.


Способ №3. Реализация механизма через расширение конфигурации (без снятия с поддержки)

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

  1. Создайте новое расширение в конфигураторе (меню Конфигурация -> Расширения конфигурации -> Добавить).
  2. Найдите в основной конфигурации справочник ДоговорыКонтрагентов, нажмите по нему правой кнопкой мыши и выберите команду Добавить в расширение.
  3. В расширении откройте модуль объекта добавленного справочника.
  4. Добавьте обработчик события ПередЗаписью с помощью аннотации &Перед.

Посмотрим на пример кода, который пишется в модуле объекта внутри расширения:


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

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


Критически важные рекомендации при разработке

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

← На главную