Обработка заполнения 1С — событие ОбработкаЗаполнения в модуле объекта. Оно есть у документов, справочников, планов видов характеристик, бизнес-процессов и других объектов, а в урезанном виде — у набора записей регистра сведений. Платформа вызывает его, когда новый объект надо заполнить: при вводе на основании, при создании из списка с отбором, по кнопке «Создать» и при вызове метода Заполнить(). Сюда кладут значения по умолчанию и перенос данных из основания — тогда заполнение одинаково работает из любой формы и из кода.
Имена в примерах условные: документы ЗаказПокупателя и РасходнаяНакладная, константа ОсновнойСклад, реквизиты перечислены в шапке листинга. Пользователи.ТекущийПользователь() — функция БСП. Если же вы искали внешнюю обработку заполнения данных, которая заполняет табличную часть по кнопке, — это дополнительная обработка БСП вида «Заполнение объекта», о ней в статье о дополнительных обработках.
| Как создают объект | Что в ДанныеЗаполнения |
|---|---|
| «Создать на основании» в форме или списке основания | Ссылка на основание |
| «Создать» в списке с отбором | Структура из элементов отбора с видом сравнения «Равно» или «В списке» с одним значением |
| «Создать» без такого отбора | Неопределено |
Форма нового объекта открыта кодом с параметром Основание | Значение параметра: ссылка, массив, структура |
Объект.Заполнить(Данные) | То, что передали, — значение любого типа |
Копирование, в том числе Ссылка.Скопировать() | Не вызывается, работает ПриКопировании |
СоздатьДокумент(), СоздатьЭлемент() | Не вызывается, пока вы сами не вызовете Заполнить() |
В управляемых формах обработка заполнения выполняется на сервере до ПриСозданииНаСервере, и форма получает уже заполненный объект. Отдельной обработки заполнения формы нет, а ОбработкаПроверкиЗаполнения — другое событие: она ничего не заполняет, а проверяет реквизиты перед записью или проведением.
В 1С 8.3 обработка заполнения — процедура ОбработкаЗаполнения(ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка). Параметра Отказ нет, поэтому запретить создание можно только исключением — стандарт 1С #std396 рекомендует именно его.
Неопределено.Истина. После выхода из обработчика платформа дозаполняет только пустые реквизиты: сначала одноимёнными значениями структуры, если у реквизита включён флажок «Заполнять из данных заполнения», затем свойством «Значение заполнения». Заполненное вашим кодом она не трогает. Ложь выключает оба шага, но создание объекта не отменяет.У стандартных реквизитов Владелец и Родитель флажок платформа ставит сама: элемент подчинённого справочника из списка с отбором по владельцу получает владельца без кода. В УТ 11.4 у заказа клиента флажок включён, например, у реквизитов Партнер, Сделка и Статус.
В УТ 11.4 и КА 2.5 обработчик объявлен по-старому: (ДанныеЗаполнения, СтандартнаяОбработка), без текста заполнения. Платформа принимает обе формы, а у набора записей регистра сведений событие только такое. Новый код пишите с тремя параметрами, а в расширении повторяйте сигнатуру типового метода.
Пользователь набрал в поле «Номенклатура» артикул, ничего не нашёл и создаёт новый элемент. Наименование подставит платформа, а код продублирует строку в артикул, если она на него похожа:
// Модуль объекта справочника Номенклатура (условный реквизит Артикул).
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
Процедура ОбработкаЗаполнения(ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка)
// Строку из поля ввода в Наименование запишет стандартная обработка
// (если наименование - основное представление и входит в «Ввод по строке»).
// Здесь только дублируем её в артикул, когда она на артикул похожа.
Если ТипЗнч(ТекстЗаполнения) <> Тип("Строка") Тогда
Возврат; // Неопределено - например, на мобильной платформе
КонецЕсли;
Текст = СокрЛП(ТекстЗаполнения);
Если Текст = "" Или СтрНайти(Текст, " ") > 0 Тогда
Возврат; // пусто или с пробелами - скорее название
КонецЕсли;
Для Позиция = 1 По СтрДлина(Текст) Цикл
Если СтрНайти("0123456789", Сред(Текст, Позиция, 1)) > 0 Тогда
Артикул = Текст; // одно слово с цифрой: «ТР-2045», «A17»
Прервать;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
#КонецЕсли
ОбработкаЗаполнения с переносом реквизитов через точку — для черновика, проверки и запрос придётся дописать.ОбработкаЗаполнения. Если реквизит заполняется «сам», а в модуле объекта кода нет, ищите здесь: в УТ 11.4 подписка «ЗаполнитьРеквизитыОбъекта» вызывает ОбщегоНазначенияУТ.ОбработкаЗаполнения и подставляет организацию, когда учёт ведётся по одной организации.Обработка заполнения документа целиком — модуль объекта накладной. Он разбирает три сценария: ввод на основании одного или нескольких заказов, «Создать» в списке, отобранном по заказу или складу, и обычное «Создать». Здесь же ПриКопировании.
// Модуль объекта документа РасходнаяНакладная.
// Шапка: Организация, Контрагент, Склад, ЗаказПокупателя, Ответственный,
// СуммаДокумента, Комментарий. Табличная часть Товары: ЗаказПокупателя,
// Номенклатура, Количество, Цена, Сумма.
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
#Область ОбработчикиСобытий
Процедура ОбработкаЗаполнения(ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка)
Заказы = Новый Массив;
ТипДанных = ТипЗнч(ДанныеЗаполнения);
Если ТипДанных = Тип("ДокументСсылка.ЗаказПокупателя") Тогда
// «Создать на основании» из заказа или Заполнить(Заказ).
Заказы.Добавить(ДанныеЗаполнения);
ИначеЕсли ТипДанных = Тип("Массив") Тогда
// Несколько заказов: Заполнить(Массив) или форма с Основание = массив.
Заказы = ДанныеЗаполнения;
ИначеЕсли ТипДанных = Тип("Структура") Тогда
// «Создать» в списке с отбором. Значения отбора платформа переносит сама,
// но после обработчика и только в пустые реквизиты. Склад к тому времени
// займёт умолчание из ЗаполнитьПустыеРеквизиты(), поэтому берём его здесь.
Если ДанныеЗаполнения.Свойство("Склад") Тогда
Склад = ДанныеЗаполнения.Склад;
КонецЕсли;
Заказ = Неопределено;
Если ДанныеЗаполнения.Свойство("ЗаказПокупателя", Заказ) И ЗначениеЗаполнено(Заказ) Тогда
Заказы.Добавить(Заказ);
КонецЕсли;
КонецЕсли;
// Неопределено - обычное «Создать»: остаются только умолчания.
Если Заказы.Количество() > 0 Тогда
ЗаполнитьПоЗаказам(Заказы);
КонецЕсли;
ЗаполнитьПустыеРеквизиты();
КонецПроцедуры
Процедура ПриКопировании(ОбъектКопирования)
// ОбработкаЗаполнения при копировании не вызывается.
// Отвязываем копию от заказов, чтобы не отгрузить их дважды.
ЗаказПокупателя = Документы.ЗаказПокупателя.ПустаяСсылка();
Для Каждого СтрокаТовара Из Товары Цикл
СтрокаТовара.ЗаказПокупателя = Документы.ЗаказПокупателя.ПустаяСсылка();
КонецЦикла;
Ответственный = Пользователи.ТекущийПользователь();
Комментарий = "";
КонецПроцедуры
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
Процедура ЗаполнитьПоЗаказам(Заказы)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Заказ.Ссылка КАК Ссылка,
| Заказ.Проведен КАК Проведен,
| Заказ.Организация КАК Организация,
| Заказ.Контрагент КАК Контрагент,
| Заказ.Склад КАК Склад
|ИЗ
| Документ.ЗаказПокупателя КАК Заказ
|ГДЕ
| Заказ.Ссылка В (&Заказы)
|
|УПОРЯДОЧИТЬ ПО
| Заказ.Дата
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| Товары.Ссылка КАК ЗаказПокупателя,
| Товары.Номенклатура КАК Номенклатура,
| Товары.Количество КАК Количество,
| Товары.Цена КАК Цена,
| Товары.Сумма КАК Сумма
|ИЗ
| Документ.ЗаказПокупателя.Товары КАК Товары
|ГДЕ
| Товары.Ссылка В (&Заказы)
| И Товары.Количество > 0
|
|УПОРЯДОЧИТЬ ПО
| Товары.Ссылка.Дата,
| Товары.НомерСтроки";
Запрос.УстановитьПараметр("Заказы", Заказы);
Результаты = Запрос.ВыполнитьПакет();
Шапки = Результаты[0].Выгрузить();
Если Шапки.Количество() = 0 Тогда
Возврат;
КонецЕсли;
Первый = Шапки[0];
Для Каждого Шапка Из Шапки Цикл
Если Не Шапка.Проведен Тогда
ВызватьИсключение СтрШаблон("Заказ %1 не проведён, отгружать по нему нельзя.", Шапка.Ссылка);
КонецЕсли;
Если Шапка.Контрагент <> Первый.Контрагент Или Шапка.Организация <> Первый.Организация Тогда
ВызватьИсключение "В одну накладную собираются заказы одного покупателя и одной организации.";
КонецЕсли;
КонецЦикла;
ЗаполнитьЗначенияСвойств(ЭтотОбъект, Первый, "Организация, Контрагент, Склад");
Если Шапки.Количество() = 1 Тогда
ЗаказПокупателя = Первый.Ссылка;
Иначе
ЗаказПокупателя = Документы.ЗаказПокупателя.ПустаяСсылка(); // заказы - в строках
КонецЕсли;
Товары.Очистить(); // Заполнить() могут вызвать и у заполненного документа
Выборка = Результаты[1].Выбрать();
Пока Выборка.Следующий() Цикл
ЗаполнитьЗначенияСвойств(Товары.Добавить(), Выборка);
КонецЦикла;
СуммаДокумента = Товары.Итог("Сумма");
КонецПроцедуры
Процедура ЗаполнитьПустыеРеквизиты()
// Умолчания - только в пустые реквизиты: основание и отбор важнее.
Если Не ЗначениеЗаполнено(Ответственный) Тогда
Ответственный = Пользователи.ТекущийПользователь();
КонецЕсли;
Если Не ЗначениеЗаполнено(Склад) Тогда
Склад = Константы.ОсновнойСклад.Получить();
КонецЕсли;
КонецПроцедуры
#КонецОбласти
#КонецЕсли
Неопределено остаются только умолчания. В рабочей конфигурации количество берут из остатка к отгрузке по регистру заказов, здесь для краткости копируются строки.ЗаполнитьПустыеРеквизиты() к этому моменту уже займёт склад основным. У контрагента умолчания нет — его платформа подставит сама. По той же причине типовая УТ 11.4 берёт партнёра из структуры отбора вручную.ДанныеЗаполнения.Товары: обращение через точку загружает объект целиком, а на структуре или Неопределено падает. Подробнее — в статье о запросах к документам, отладить запрос можно в консоли запросов.ВызватьИсключение для непроведённого заказа: при интерактивном вводе форма не откроется, пользователь увидит текст исключения.Товары.Очистить() нужен, потому что Заполнить() вызывают и для заполненного документа (команда перезаполнения ниже).ЗаполнитьПустыеРеквизиты() — общий шаг по стандарту: умолчания только в незаполненные реквизиты, чтобы не затереть основание.ПриКопировании отвязывает копию от заказов, иначе один заказ отгрузят дважды.Метод Заполнить() запускает то же событие, что интерактивный ввод, поэтому логика из модуля объекта работает и для документов, созданных кодом. Модуль менеджера накладной:
// Модуль менеджера документа РасходнаяНакладная.
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
#Область ПрограммныйИнтерфейс
// Создаёт и проводит накладную по заказу или массиву заказов.
// Возвращает ссылку на новый документ.
Функция СоздатьПоЗаказам(Заказы) Экспорт
Накладная = Документы.РасходнаяНакладная.СоздатьДокумент();
// Дату - до заполнения: от неё может зависеть то, что считает обработчик.
Накладная.Дата = ТекущаяДатаСеанса();
// СоздатьДокумент() обработку заполнения не запускает - вызываем сами.
Накладная.Заполнить(Заказы);
Если Накладная.Товары.Количество() = 0 Тогда
ВызватьИсключение "В заказах нет строк к отгрузке.";
КонецЕсли;
Накладная.Записать(РежимЗаписиДокумента.Проведение);
Возврат Накладная.Ссылка;
КонецФункции
// Пустая накладная для контрагента - с теми же умолчаниями, что кнопка «Создать».
Функция СоздатьДляКонтрагента(Контрагент, Комментарий = "") Экспорт
Накладная = Документы.РасходнаяНакладная.СоздатьДокумент();
Накладная.Дата = ТекущаяДатаСеанса();
Накладная.Заполнить(Неопределено);
Накладная.Контрагент = Контрагент;
Накладная.Комментарий = Комментарий;
Накладная.Записать(РежимЗаписиДокумента.Запись);
Возврат Накладная.Ссылка;
КонецФункции
#КонецОбласти
#КонецЕсли
Заполнить(Неопределено) даёт те же умолчания, что и кнопка «Создать». С клиента функции вызывают через общий модуль с флажком «Вызов сервера».
Параметр формы Основание принимает значение любого типа и попадает в ДанныеЗаполнения как есть. Команда в форме списка заказов собирает выделенные строки и открывает одну накладную на все:
// Модуль формы списка документа ЗаказПокупателя.
// Команда «Отгрузить выделенные»: одна накладная по нескольким заказам.
&НаКлиенте
Процедура ОтгрузитьВыделенные(Команда)
Заказы = Новый Массив;
Для Каждого Ключ Из Элементы.Список.ВыделенныеСтроки Цикл
Если ТипЗнч(Ключ) = Тип("ДокументСсылка.ЗаказПокупателя") Тогда
Заказы.Добавить(Ключ);
КонецЕсли;
КонецЦикла;
Если Заказы.Количество() = 0 Тогда
ПоказатьПредупреждение(, "Выделите в списке хотя бы один заказ.");
Возврат;
КонецЕсли;
// Параметр Основание форма передаст в Заполнить(), а тот - в ДанныеЗаполнения.
ОткрытьФорму("Документ.РасходнаяНакладная.ФормаОбъекта",
Новый Структура("Основание", Заказы), ЭтотОбъект);
КонецПроцедуры
| Событие | Модуль | Когда | Что там делать |
|---|---|---|---|
| ОбработкаЗаполнения | Объекта | Новый объект: основание, отбор, «Создать», Заполнить() | Умолчания, перенос из основания, запрет ввода |
| ПриКопировании | Объекта | Копия: интерактивно и Скопировать() | Очистить то, что копия наследовать не должна |
| ПриСозданииНаСервере | Формы | Каждое открытие формы: новый, копия, существующий | Видимость, подсказки, параметры выбора |
Для нового объекта порядок такой: ОбработкаЗаполнения → стандартное дозаполнение → ПриСозданииНаСервере; для копии — ПриКопировании → ПриСозданииНаСервере. Как создан объект, форма узнаёт по параметрам Основание и ЗначениеКопирования. А чтобы перезаполнить открытый документ, вызывают Заполнить() у объекта, полученного из реквизита формы:
// Модуль формы документа РасходнаяНакладная.
// На форме: декорация Подсказка, колонка ТоварыЗаказПокупателя,
// команда ПерезаполнитьПоЗаказу.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Объект уже заполнен: у нового отработала ОбработкаЗаполнения,
// у копии - ПриКопировании. Здесь - только то, что касается формы.
Если ЗначениеЗаполнено(Параметры.ЗначениеКопирования) Тогда
Элементы.Подсказка.Заголовок = "Копия: проверьте склад и количество.";
ИначеЕсли ЗначениеЗаполнено(Параметры.Основание) Тогда
Элементы.Подсказка.Заголовок = "Заполнено по заказу. При частичной отгрузке уменьшите количество.";
Иначе
Элементы.Подсказка.Видимость = Ложь;
КонецЕсли;
// Колонка заказа нужна, когда накладная собрана из нескольких заказов.
Элементы.ТоварыЗаказПокупателя.Видимость = Не ЗначениеЗаполнено(Объект.ЗаказПокупателя);
КонецПроцедуры
&НаКлиенте
Процедура ПерезаполнитьПоЗаказу(Команда)
Если Не ЗначениеЗаполнено(Объект.ЗаказПокупателя) Тогда
ПоказатьПредупреждение(, "Сначала выберите заказ покупателя.");
Возврат;
КонецЕсли;
Оповещение = Новый ОписаниеОповещения("ПерезаполнитьПоЗаказуЗавершение", ЭтотОбъект);
ПоказатьВопрос(Оповещение, "Шапка и товары будут заполнены заново по заказу. Продолжить?",
РежимДиалогаВопрос.ДаНет);
КонецПроцедуры
&НаКлиенте
Процедура ПерезаполнитьПоЗаказуЗавершение(Ответ, ДополнительныеПараметры) Экспорт
Если Ответ = КодВозвратаДиалога.Да Тогда
ПерезаполнитьПоЗаказуНаСервере();
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура ПерезаполнитьПоЗаказуНаСервере()
// Тот же код, что при вводе на основании: Заполнить() вызывает ОбработкаЗаполнения.
ДокументОбъект = РеквизитФормыВЗначение("Объект");
ДокументОбъект.Заполнить(ДокументОбъект.ЗаказПокупателя);
ЗначениеВРеквизитФормы(ДокументОбъект, "Объект");
Модифицированность = Истина;
КонецПроцедуры
В типовой без снятия с поддержки обработку заполнения дополняют расширением: заимствуют документ и перехватывают метод аннотацией &После (подробно — в статье о расширении конфигурации). Пример — заказ клиента в УТ 11.4.
// Расширение для УТ 11.4: модуль объекта заимствованного документа ЗаказКлиента.
// Реквизит Расш1_КаналПродаж (справочник расширения) добавлен в ЗаказКлиента,
// справочник Партнеры и документ КоммерческоеПредложениеКлиенту.
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
&После("ОбработкаЗаполнения")
Процедура Расш1_ОбработкаЗаполнения(ДанныеЗаполнения, СтандартнаяОбработка)
// Параметры - как у типового метода: в УТ 11.4 их два, без ТекстЗаполнения.
// Типовой код уже отработал и подставил партнёра из основания или отбора.
Если ЗначениеЗаполнено(Расш1_КаналПродаж) Тогда
Возврат; // повторное Заполнить() не меняет выбранный канал
КонецЕсли;
ТипДанных = ТипЗнч(ДанныеЗаполнения);
Если ТипДанных = Тип("Структура") И ДанныеЗаполнения.Свойство("Расш1_КаналПродаж") Тогда
// Список отобран по каналу: берём сами, иначе ниже займёт канал партнёра.
Расш1_КаналПродаж = ДанныеЗаполнения.Расш1_КаналПродаж;
ИначеЕсли ТипДанных = Тип("ДокументСсылка.КоммерческоеПредложениеКлиенту") Тогда
Расш1_КаналПродаж = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(ДанныеЗаполнения, "Расш1_КаналПродаж");
КонецЕсли;
Если Не ЗначениеЗаполнено(Расш1_КаналПродаж) И ЗначениеЗаполнено(Партнер) Тогда
Расш1_КаналПродаж = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Партнер, "Расш1_КаналПродаж");
КонецЕсли;
КонецПроцедуры
#КонецЕсли
ТекстЗаполнения. Сверяйте сигнатуру в своём релизе: при расхождении расширение не применится.&После выполняется после типового кода, реквизиты шапки уже заполнены. Опирайтесь на них (здесь — Партнер), а не на ветки типового обработчика: в КА 2.5 заказ клиента разбирает основания иначе, чем в УТ 11.4.Основание структуру с ключом ДокументОснование, а в нём ссылку или массив заказов.ОбработкаЗаполнения.ДанныеЗаполнения.Товары, а документ создали обычным «Создать» (Неопределено). Из списка с отбором тот же код упадёт с ошибкой «Поле объекта не обнаружено (Товары)»: в структуре нет такого ключа.СоздатьДокумент() обработку заполнения не вызывает — добавьте Заполнить(Неопределено) или Заполнить(Основание).СтандартнаяОбработка = Ложь или сам раньше заполнил реквизит умолчанием.ОбработкаЗаполнения, а при копировании работает только ПриКопировании.ПриСозданииНаСервере. Не сработают при создании кодом, а проверка Объект.Ссылка.Пустая() истинна и для копии — скопированные значения перезапишутся.ТипЗнч(ДанныеЗаполнения) = Тип("ДокументСсылка.ЗаказКлиента") не проходит: типовая команда передала структуру.В ОбработкаЗаполнения проверьте основание и вызовите исключение с понятным текстом, как в листинге выше. Стандарт #std396 рекомендует именно так, а не отдельные команды с проверками. Так же запрещают ввод на основании группы справочника: команда «Создать на основании» групп от элементов не отличает.
Постоянное значение (вид операции, флажок) — в свойстве «Значение заполнения». Вычисляемое (текущий пользователь, склад из константы) — в ОбработкаЗаполнения с проверкой на пустоту. В ПриСозданииНаСервере — только то, что касается формы.
Списка «Вводится на основании» мало: в типовых формах меню строит БСП (общий модуль СозданиеНаОсновании). В УТ 11.4 команды перечисляет процедура ДобавитьКомандыСозданияНаОсновании модуля менеджера документа-основания, а основание зарегистрировано в СозданиеНаОснованииПереопределяемый.ПриОпределенииОбъектовСКомандамиСозданияНаОсновании. Подробнее о подсистемах — в статье о БСП.
Да, у набора записей. Она срабатывает при Заполнить() набора или менеджера записи и при вводе новой записи из списка: значения отбора попадают в одноимённые поля записей.
Связать типовые документы вводом на основании, перенести табличные части по своим правилам или дописать заполнение в УТ, КА и ERP расширением без снятия с поддержки лучше поручить программисту, который знает типовую изнутри. Опишите задачу в разделе услуг по доработке 1С или разместите задание бесплатно: оценка бесплатная, ответ — в течение рабочего дня.
Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.