Как переопределить данные заполнения при вводе на основании в 1С 8.3

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

При разработке в среде 1С:Предприятие 8.3 часто возникает задача создания одного документа на основании другого. Стандартный механизм платформы позволяет легко связать объекты через метаданные, однако типовая логика заполнения не всегда удовлетворяет требованиям бизнеса. Особенно это актуально, когда мы работаем с типовыми конфигурациями, такими как УТ 11.4, ERP или КА, где изменять основной код крайне нежелательно. В данной статье мы разберем, как грамотно переопределить ДанныеЗаполнения, передать нужные структуры и корректно заполнить целевой документ, используя расширения и программные методы.

Постановка задачи и анализ механизмов

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

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

Решение 1: Использование расширения с аннотацией &После

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

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


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

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

Решение 2: Использование аннотации &Вместо и контроль вызова

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

Проанализируем пример реализации:


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

Важный нюанс: Если вы передаете в ДанныеЗаполнения не ссылку, а Структуру, типовой код может выдать ошибку, так как он ожидает ссылку. В этом случае использование &Вместо с отказом от ПродолжитьВызов становится единственным способом избежать падения системы.

Решение 3: Программное формирование данных в источнике

Иногда нам нужно передать из источника не просто ссылку, а подготовленный набор данных (например, уже рассчитанные остатки или отфильтрованные строки). Для этого мы можем переопределить команду "Создать на основании" в документе-источнике.

Выполним следующие шаги:

  1. В документе ЗаявкаВРозницу создадим собственную команду СоздатьОтчетОПродажах.
  2. В модуле команды опишем программное открытие формы нового документа.
  3. В качестве параметра заполнения передадим не ссылку, а структуру.

Пример кода в модуле команды:


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

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

Архитектурные рекомендации и подводные камни

Разберем несколько важных моментов, которые помогут избежать ошибок при реализации:

  1. Подписки на события: Можно использовать подписку на событие ОбработкаЗаполнения. Она удобна тем, что не привязана к конкретному расширению. Однако помните: подписки всегда срабатывают после кода в модуле объекта. Если типовой код вызовет исключение при попытке обработать неизвестный тип данных, подписка просто не успеет запуститься.
  2. Сериализация данных: Если ваше решение должно работать в Web-клиенте, помните, что сложные типы данных (например, ТаблицаЗначений) не могут быть переданы напрямую между клиентом и сервером через параметры формы. Используйте массив структур или фиксированные массивы.
  3. Использование БСП: В современных конфигурациях (УТ 11, ERP 2) механизм заполнения часто вынесен в общий модуль ЗаполнениеОбъектовПереопределяемый. Проверьте, возможно ли добавить правила заполнения через этот механизм. Это позволит настраивать связи между документами вообще без написания кода в модулях документов.
  4. СтандартнаяОбработка: Если вы полностью заполняете документ в расширении, не забывайте устанавливать СтандартнаяОбработка = Ложь, чтобы система не пыталась выполнить стандартные механизмы, которые могут перезатереть ваши данные.

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

← На главную