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