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

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

При разработке конфигураций на платформе 1С:Предприятие 8 перед разработчиком часто встает дилемма: где именно разместить код, отвечающий за заполнение реквизитов нового документа? С одной стороны, существует стандартное событие ОбработкаЗаполнения в модуле объекта, с другой — велик соблазн написать процедуру в общем модуле или вовсе выполнить заполнение непосредственно в месте создания объекта. В этой статье мы подробно разберем, какой подход считается правильным с точки зрения стандартов разработки 1С и принципов объектно-ориентированного проектирования.

Понимание механизмов платформы: ОбработкаЗаполнения и метод Заполнить

Для начала проанализируем ситуацию с точки зрения платформы. Событие ОбработкаЗаполнения возникает в нескольких случаях: при вводе документа на основании другого объекта, при интерактивном создании нового документа (когда в метаданных указаны значения заполнения), а также при программном вызове метода объекта Заполнить().

Важное уточнение: если вы просто создаете документ программно с помощью Документы.ИмяДокумента.СоздатьДокумент(), событие ОбработкаЗаполнения само по себе не вызывается. Чтобы инициализировать документ так же, как это делает платформа при интерактивном вводе, необходимо явно вызвать метод Заполнить().

Рассмотрим пример правильной программной инициализации:


НовыйДокумент = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
// Передаем Неопределено, если нет конкретного основания, 
// чтобы сработали стандартные настройки реквизитов
НовыйДокумент.Заполнить(Неопределено); 
НовыйДокумент.Записать();

Соблюдение стандарта разработки №451

Согласно стандарту разработки 1С под номером 451, при программном создании объекта следует всегда явно вызывать метод объекта Заполнить. Рассмотрим подробнее, почему это критично:

  1. Значение заполнения: В свойствах реквизитов объекта в конфигураторе часто устанавливается флаг "Значение заполнения". Если не вызвать Заполнить(), эти реквизиты останутся пустыми, что может привести к некорректному состоянию данных.
  2. Подписки на события: Метод Заполнить() вызывает не только внутренний код модуля, но и внешние подписки на событие ОбработкаЗаполнения. Это позволяет расширениям или сторонним подсистемам внедрять свою логику без изменения кода самого документа.
  3. Единообразие логики: Использование единой точки входа гарантирует, что документ, созданный программно, будет идентичен документу, созданному пользователем вручную.

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

Архитектурный выбор: Модуль объекта против Общего модуля

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

Подход 1: "Толстая модель" (Information Expert)

Согласно паттерну Information Expert (Информационный эксперт), логика должна находиться там, где сосредоточены данные. Поскольку документ лучше всех "знает" структуру своих реквизитов и правила их взаимосвязи, код заполнения логично размещать в его модуле объекта в процедуре ОбработкаЗаполнения.

Подход 2: Сервисная архитектура (Service Layer)

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

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

Рассмотрим на примере:


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

Использование универсальной структуры ПараметрыЗаполнения

Современная практика разработки (особенно в типовых конфигурациях на базе БСП) предполагает передачу в ОбработкаЗаполнения не просто ссылки-основания, а Структуры. Это позволяет гибко управлять процессом заполнения.

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

  1. Основание: Сама ссылка на документ, на основании которого создается новый.
  2. Дополнительные параметры: Например, флаги ПропуститьПроверкуЛимитов или УстановитьСтатусЧерновик.
  3. Значения по умолчанию: Если нужно заполнить специфические поля, которых нет в объекте-основании.

Пример программного вызова с передачей параметров:


ПараметрыЗаполнения = Новый Структура;
ПараметрыЗаполнения.Вставить("Основание", СсылкаНаЗаказ);
ПараметрыЗаполнения.Вставить("СкладОтгрузки", НужныйСклад);
ПараметрыЗаполнения.Вставить("ЭтоСрочныйЗаказ", Истина);

НовыйДокумент = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
НовыйДокумент.Заполнить(ПараметрыЗаполнения);

Преимущества расширяемости

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

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

Инициализация при копировании

Не стоит забывать, что ОбработкаЗаполнения вызывается и при копировании объекта. В этом случае в ДанныеЗаполнения передается ссылка на копируемый объект. Это идеальное место для того, чтобы:

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

Итоги и рекомендации

Подводя итог нашему анализу, сформулируем основные правила программного заполнения документов:

  1. Всегда вызывайте метод Заполнить() при программном создании документа. Это гарантирует соблюдение стандартов 1С и корректную работу механизмов БСП.
  2. Используйте ОбработкаЗаполнения как центральную точку входа для логики инициализации объекта.
  3. Выносите тяжелую логику в общие модули, но вызывайте их из модуля объекта. Это позволит избежать "раздувания" кода документа и обеспечит возможность переиспользования алгоритмов.
  4. Передавайте структуру параметров, если стандартного значения-основания недостаточно для описания логики заполнения.
  5. Учитывайте контекст копирования внутри обработчика, чтобы гарантировать чистоту данных при создании новых объектов на основе существующих.

Такой подход делает код надежным, расширяемым и соответствующим профессиональным стандартам разработки на платформе 1С:Предприятие.

← На главную