Разработка и Конфигурация · 12 мин
Как программно создать документ на основании в 1С 8.3
Создание документа на основании в 1С 8.3: методы Заполнить(), обработчики заполнения, ОбработкаЗаполнения, проверка результата и типичные ошибки разработчиков.
Создание документа на основании другого документа — одна из базовых операций при разработке и доработке конфигураций 1С 8.3. Типовой пример: по «Заказу покупателя» нужно программно сформировать «Реализацию товаров и услуг» или «Счет на оплату», перенеся шапку и табличную часть. Для этого платформа предоставляет встроенный механизм ввода на основании и набор программных методов.
Есть два принципиально разных подхода. Первый — интерактивный: пользователь нажимает кнопку «Создать на основании», и платформа вызывает обработчик заполнения. Второй — полностью программный: код создает новый объект документа, вызывает у него метод заполнения с основанием и записывает результат. Оба подхода опираются на один и тот же механизм — процедуру ОбработкаЗаполнения в модуле объекта документа.
Ниже разобраны оба варианта, настройка обработчика заполнения, проверка результата, типичные ошибки и ограничения, о которых нужно помнить при доработке типовых конфигураций.
Как устроен механизм ввода на основании в 1С 8.3
Механизм ввода на основании состоит из трех элементов. Первый — свойство документа «Вводится на основании» в конфигураторе, где перечисляются типы документов-оснований. Второй — процедура ОбработкаЗаполнения(ДанныеЗаполнения, СтандартнаяОбработка) в модуле объекта документа, которая вызывается платформой при создании документа с параметром заполнения. Третий — метод Заполнить(), который программно инициирует тот же процесс.
Важно понимать: сам по себе вызов Заполнить(Основание) ничего волшебного не делает. Он лишь передает основание в обработчик заполнения. Если в ОбработкаЗаполнения не описана логика переноса данных, документ останется пустым. В типовых конфигурациях (УТ, ERP, БП) эти обработчики уже реализованы, и программный вызов использует штатную логику, включая проверки, отборы и служебные заполнения.
Программное создание документа на основании: базовый код
Минимальный сценарий выглядит так: получить объект-основание, создать новый документ, заполнить его и записать. Ниже пример для создания реализации на основании заказа покупателя.
ЗаказОбъект = СсылкаНаЗаказ.ПолучитьОбъект();
НовыйДокумент = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
НовыйДокумент.Дата = ТекущаяДатаСеанса();
НовыйДокумент.Заполнить(СсылкаНаЗаказ);
НовыйДокумент.Записать(РежимЗаписиДокумента.Проведение);
Обратите внимание на несколько деталей. В Заполнить() обычно передается ссылка на основание, а не объект — обработчики типовых конфигураций рассчитаны именно на ссылку. Дату документа лучше установить до вызова Заполнить(), так как от даты могут зависеть курсы валют, договоры и другие заполняемые реквизиты. Режим записи выбирайте осознанно: Проведение сразу формирует движения, Запись — только сохраняет документ.
- 1Получите ссылку на документ-основание и убедитесь, что он проведен
- 2Создайте новый документ методом СоздатьДокумент()
- 3Установите дату и организацию, если они влияют на заполнение
- 4Вызовите Заполнить(СсылкаНаОснование)
- 5Проверьте, что реквизиты и табличные части заполнены
- 6Запишите документ в нужном режиме и обработайте возможные исключения
Если документ должен создаваться в фоне или пакетно (например, обработкой по списку заказов), оберните запись каждого документа в попытку-исключение и фиксируйте ошибки в журнале регистрации, чтобы один проблемный заказ не прервал всю обработку.
Настройка обработчика ОбработкаЗаполнения
Если вы разрабатываете собственные документы или добавляете новый вид основания, логику переноса данных нужно описать в модуле объекта создаваемого документа:
Процедура ОбработкаЗаполнения(ДанныеЗаполнения, СтандартнаяОбработка)
Если ТипЗнч(ДанныеЗаполнения) = Тип("ДокументСсылка.ЗаказПокупателя") Тогда
Организация = ДанныеЗаполнения.Организация;
Контрагент = ДанныеЗаполнения.Контрагент;
Договор = ДанныеЗаполнения.Договор;
Для Каждого СтрокаТовара Из ДанныеЗаполнения.Товары Цикл
НоваяСтрока = Товары.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаТовара);
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Метод ЗаполнитьЗначенияСвойств() переносит одноименные поля, поэтому старайтесь называть колонки табличных частей одинаково в основании и в создаваемом документе — это заметно упрощает код. Реквизиты, которые совпадать не должны (количество к отгрузке вместо заказанного, пересчитанные суммы), заполняйте отдельно после общего переноса.
Не забудьте в конфигураторе у документа на закладке «Ввод на основании» указать допустимые типы оснований — тогда документ появится в стандартной кнопке «Создать на основании», и интерактивный сценарий заработает без дополнительного кода.
Создание документа интерактивно: команда «Создать на основании»
Для пользовательского сценария достаточно настройки в конфигураторе: у документа-основания на закладке «Ввод на основании» отметьте создаваемые документы в поле «Является основанием для». Платформа автоматически сформирует подменю «Создать на основании» в форме списка и форме документа, а при выборе пункта вызовет ОбработкаЗаполнения с переданной ссылкой.
Если стандартной кнопки недостаточно — например, нужно создавать документ по нескольким выделенным строкам списка или с предварительными вопросами пользователю — добавьте свою команду формы. В обработчике команды программно создайте документ, заполните его и откройте форму нового объекта через ОткрытьФорму() либо покажите пользователю созданный объект через ПоказатьЗначение().
Открытие формы нового документа с заполнением
Часто требуется не записывать документ сразу, а открыть пользователю заполненную форму для проверки. Для этого используются параметры формы:
ПараметрыФормы = Новый Структура("Основание", СсылкаНаЗаказ);
ОткрытьФорму("Документ.РеализацияТоваровУслуг.ФормаОбъекта", ПараметрыФормы);
Параметр с ключом «Основание» — стандартный: платформа сама передаст его в ОбработкаЗаполнения при создании формы нового объекта. Документ при этом еще не записан в базу — пользователь может отредактировать данные или закрыть форму без сохранения.
Проверка результата и обработка ошибок
После вызова Заполнить() не полагайтесь на то, что все прошло успешно. Обработчики типовых конфигураций могут молча не заполнить документ: например, если заказ не проведен, не оплачен по условиям конфигурации или уже полностью отгружен. Поэтому перед записью проверяйте ключевые реквизиты и непустоту табличных частей.
Как проверить результат
Содержит строки с номенклатурой и количеством
Пустая табличная часть — заполнение не сработало
Совпадают с основанием
Пустые или подставлены значения по умолчанию
Документ записан без исключений, движения сформированы
Ошибка проведения — проверьте остатки, периоды и заполненность обязательных реквизитов
Для контроля проведения используйте попытку-исключение и анализ возвращаемого результата. Если документ записывается в транзакции вместе с другими операциями, помните: откат транзакции отменит и запись документа, поэтому сообщения пользователю выводите после успешной фиксации.
Ограничения и альтернативные подходы
Механизм Заполнить() подходит, когда логика переноса уже реализована или ее несложно написать. Но есть ситуации, где лучше выбрать другой путь. Если нужно создать документ, сильно отличающийся от основания по структуре, проще заполнить реквизиты вручную в коде, не вызывая типовой обработчик. Если требуется массовое создание по сложным правилам с отборами остатков — используйте запросы к регистрам накопления (например, «ЗаказыПокупателей»), чтобы отгружать только фактически неотгруженные остатки.
Сравнение вариантов
Быстро и использует типовую логику; ограничение — поведение жестко задано обработчиком конфигурации
Полный контроль над результатом; требует самостоятельно переносить все поля и следить за изменениями структуры при обновлениях
Пользователь проверяет документ до записи; не подходит для пакетных и фоновых сценариев
Еще одно ограничение — права. Пользователь, от имени которого выполняется код, должен иметь права на добавление и проведение создаваемого документа, иначе запись завершится ошибкой. В фоновых заданиях проверяйте, под каким пользователем выполняется задание.
Отладка и полезные приемы
Для отладки обработчика заполнения поставьте точку останова в ОбработкаЗаполнения модуля объекта и создайте документ интерактивно через «Создать на основании» — так вы увидите, какие данные приходят в ДанныеЗаполнения и какая ветка кода срабатывает. В управляемом приложении отладку серверного кода включайте через настройки конфигуратора.
Полезный прием для предотвращения дублей: перед созданием документа запросом проверьте, существует ли уже документ нужного вида с таким основанием (в типовых конфигурациях часто есть реквизит «ДокументОснование» или критерий отбора «СвязанныеДокументы»). Это особенно важно для регламентных заданий, которые могут перезапускаться после сбоев.
Что важно запомнить
Программное создание на основании — это СоздатьДокумент() + Заполнить(СсылкаНаОснование) + Записать(). Логика переноса живет в ОбработкаЗаполнения, типовые обработчики дорабатывайте через расширения, результат всегда проверяйте перед записью, а массовые операции сначала тестируйте на копии базы.
Частые вопросы
Почему Заполнить() не заполняет документ, хотя основание передано?
Чаще всего передан объект вместо ссылки или в ОбработкаЗаполнения нет ветки для данного типа основания. Проверьте тип параметра через ТипЗнч() в отладчике и убедитесь, что обработчик содержит условие для типа вашего документа-основания. В типовых конфигурациях также могут срабатывать внутренние отборы — например, незаполнение при полностью отгруженном заказе.
Как создать документ на основании нескольких документов сразу?
Стандартный механизм принимает одно основание. Для нескольких передайте в Заполнить() массив или структуру и обработайте этот тип в ОбработкаЗаполнения — этот прием используется в типовых конфигурациях. Либо создайте документ по первому основанию, а строки остальных добавьте в табличную часть вручную в цикле.
Чем отличается Заполнить() от копирования документа?
Копирование переносит данные того же вида документа через параметр «ЗначениеКопирования», а Заполнить() с основанием создает документ другого вида по правилам ОбработкаЗаполнения. Для копирования программно используйте метод Скопировать() у объекта документа.
Как сделать, чтобы документ создавался, но не проводился автоматически?
Вызывайте Записать() с режимом РежимЗаписиДокумента.Запись вместо Проведение. Документ сохранится в базе без движений, и пользователь сможет проверить и провести его вручную. Это безопасный вариант для первых этапов внедрения автоматического создания.
Можно ли доработать ввод на основании в типовой конфигурации без снятия с поддержки?
Да, через расширение конфигурации. Добавьте в расширение модуль объекта документа и переопределите ОбработкаЗаполнения с аннотацией &После или &Вместо, вызвав типовую процедуру при необходимости. Так конфигурация останется на полной поддержке и будет обновляться штатно.
Как найти все документы, созданные на основании конкретного документа?
Если в создаваемых документах есть реквизит основания — запросом по этому реквизиту. Универсальный способ в типовых конфигурациях — критерий отбора «СвязанныеДокументы» или отчет «Связанные документы» в интерфейсе. Программно можно использовать метод ПолучитьОбъектыПоКритериюОтбора() либо построить запрос по таблицам критерия отбора.