Как правильно изменить реквизиты нового документа, созданного на основании другого, в 1С 8.3 до его записи?

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

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

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


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    Если Объект.Основание.Пустая() Тогда
        Возврат;
    КонецЕсли;

    ДокументОснование = Объект.Основание.ПолучитьОбъект();

    // Попытка изменить склад
    // Объект.Склад = СкладПоступления; // Здесь возникнет ошибка
    // Объект.Записать(); // Здесь возникнет ошибка, т.к. документ еще не записан

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

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

Использование обработчика ОбработкаЗаполнения

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

  1. Когда вызывается ОбработкаЗаполнения?

    Данный обработчик активируется в нескольких сценариях:

    • При создании нового документа на основании существующего. В этом случае в параметр Основание передается ссылка на документ-основание.
    • При заполнении нового документа данными по умолчанию (например, при вызове метода Заполнить()).

    Именно поэтому ОбработкаЗаполнения идеально подходит для нашего случая, когда документ "Поступление товаров и услуг" создается на основании "Заказа клиента".

  2. Доступ к документу-приемнику и документу-основанию

    Внутри обработчика ОбработкаЗаполнения мы имеем доступ к следующим объектам:

    • ЭтотОбъект: Это сам объект нового документа (документа-приемника), который мы создаем и хотим изменить. Мы можем напрямую обращаться к его реквизитам.
    • Основание: Это параметр, который содержит ссылку на документ, на основании которого создается новый документ. Через эту ссылку мы можем получить доступ к данным документа-основания.

Примеры реализации

Давайте рассмотрим несколько практических примеров того, как мы можем использовать обработчик ОбработкаЗаполнения (по аналогии с тем, как реализовано создание счета на оплату на основании реализации) для изменения реквизита "Склад" в документе "ПоступлениеТоваровУслуг", создаваемом на основании "ЗаказКлиента".

Пример 1: Изменение склада на фиксированное значение

Предположим, нам всегда нужно устанавливать определенный склад, например, "Основной склад", при создании "Поступления" на основании "Заказа клиента". Мы можем реализовать это следующим образом:


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

        // Проверяем, что склад найден, чтобы избежать ошибок
        Если СкладПоступления.Пустая() Тогда
            Предупреждение("Склад 'Основной склад' не найден в справочнике Склады!");
        Иначе
            // Устанавливаем найденный склад для текущего документа поступления
            ЭтотОбъект.Склад = СкладПоступления;
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

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

Пример 2: Получение склада из документа-основания

Часто возникает ситуация, когда склад для нового документа должен зависеть от данных документа-основания. Например, если в "Заказе клиента" уже указан "Склад отгрузки", логично использовать именно его как "Склад" в "Поступлении товаров и услуг". Это обеспечивает большую гибкость и автоматизацию. Рассмотрим такой вариант:


Процедура ОбработкаЗаполнения(Основание)
    Если ТипЗнч(Основание) = Тип("ДокументСсылка.ЗаказКлиента") Тогда
        // Получаем объект документа-основания для доступа к его реквизитам
        Заказ = Основание.ПолучитьОбъект();

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

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

Дополнительные рекомендации

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

Итоги и заключение

Мы выяснили, что для эффективного и корректного изменения реквизитов нового документа, созданного на основании другого, в 1С:Предприятие 8.3 следует использовать обработчик события ОбработкаЗаполнения. Этот обработчик предоставляет нам идеальный момент для вмешательства в процесс заполнения документа, позволяя настроить его поведение до взаимодействия с пользователем. Применяя предложенные подходы, мы сможем автоматизировать рутинные операции, повысить удобство работы пользователей и обеспечить целостность данных в нашей информационной системе.

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

← На главную