Как автоматически создать документ «Установка цен» при проведении «Поступления товаров» в 1С?

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

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

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

Разбор типичных ошибок: почему документ не создается?

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

  1. Неверное расположение кода. Это самая популярная ошибка. Если написать процедуру создания нового документа внутри модуля объекта самого создаваемого документа (например, в модуле ДокументУстановкиЦен), система никогда её не вызовет. Документ-источник (ПоступлениеТоваров) просто «не знает» о существовании этого кода. Процедура инициализации должна запускаться из модуля документа-источника или через общие механизмы платформы.
  2. Ошибки в логических условиях и синтаксисе. Конструкции вида Если ЭтотОбъект.ПослуплениеТоваров = Истина Тогда содержат сразу несколько критических ошибок. Во-первых, обратите внимание на опечатку в слове «Послупление» — такие досадные промахи часто блокируют выполнение условий. Во-вторых, свойство ЭтотОбъект внутри модуля создаваемого документа указывает на сам создаваемый документ, у которого, скорее всего, нет и не может быть реквизита с типом Булево для такой проверки.
  3. Лишние транзакционные операции. Попытка дважды записать документ подряд, сначала через Записать(РежимЗаписиДокумента.Запись), а затем через Записать(РежимЗаписиДокумента.Проведение), избыточна и создает лишнюю нагрузку на СУБД. Достаточно сразу вызвать запись с режимом проведения.

Архитектурный подход: пишем надежное решение

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

Реализация через подписку на события

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

Создадим подписку на событие со следующими свойствами:

Рассмотрим подробный пример кода, реализующий всю необходимую бизнес-логику:


Процедура ПриПроведенииПоступленияСоздатьУстановкуЦенОбработкаПроведения(Источник, Отказ, РежимПроведения) Экспорт

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

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

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

Связь документов в структуре подчиненности

Чтобы пользователи могли легко переходить из документа «Поступление товаров» в созданный документ установки цен, обязательно настройте их взаимосвязь. Для этого в документе УстановкаЦенНоменклатуры должен быть добавлен реквизит ДокументОснование с типом ссылки на документ поступления.

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

Обработка отмены проведения и удаления

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

Создадим вторую подписку на событие:

Код обработчика в общем модуле будет выглядеть следующим образом:


Процедура ПриИзмененииСтатусаПоступленияКорректироватьУстановкуЦенПередЗаписью(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт

	Если Источник.ОбменДанными.Загрузка Тогда
		Возврат;
	КонецЕсли;

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

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

Штатные альтернативы в современных конфигурациях

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

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

← На главную