Новый документ в конфигураторе 1С 8.3: от объекта метаданных до проведения по регистрам
Содержание
Новый тип документа создают в конфигураторе: в дереве метаданных правой кнопкой по ветке Документы → Добавить. Откроется окно редактирования объекта с вкладками — на них задают имя, реквизиты шапки, табличные части, нумерацию, регистры для движений и формы. Логику проведения пишут в модуле объекта, в обработчике ОбработкаПроведения.
Всё описанное относится к платформе 8.3 в целом и не зависит от конкретной конфигурации: так же собирают документ и в своей разработке, и в расширении к Бухгалтерии или Управлению торговлей. Порядок шагов — от объекта метаданных к коду проведения.
Подготовка: где создавать документ и как не сломать обновления
Перед тем как нажать Добавить, решите, куда вы вносите изменение. От этого зависит, как база будет обновляться дальше.
| Ситуация | Где создавать | Почему |
|---|---|---|
| Своя конфигурация с нуля | Прямо в основной конфигурации | Поддержки поставщика нет, ограничений тоже |
| Типовая (БП, ЗУП, УТ) на поддержке | В расширении конфигурации | Основная конфигурация остаётся на поддержке, обновления ставятся без сравнения-объединения |
| Типовая, уже снятая с поддержки | В основной или в расширении | Расширение всё равно проще переносить между релизами |
Расширения появились в платформе 8.3.6. Документ, добавленный в расширение, полноценный: у него свои реквизиты, формы, модули и права. Регистры для его движений тоже можно создать в расширении.
Перед изменением конфигурации рабочей базы сделайте выгрузку в .dt. Для обновления структуры базы при добавлении нового объекта нужен монопольный доступ, если в базе работают пользователи — планируйте это на нерабочее время.
Создание объекта метаданных и его основные свойства
Объект создают в ветке Документы дерева конфигурации. На вкладке Основные заполняют:
- 🏷️ Имя — идентификатор для кода, без пробелов:
ПриходТовара. Его потом пишут вДокументы.ПриходТовара. - 📝 Синоним — то, что видит пользователь: «Приход товара».
- 📄 Представление объекта и Представление списка — заголовки формы документа и формы списка. Если не заполнить, платформа возьмёт синоним.
На вкладке Подсистемы отметьте раздел, в котором документ появится в командном интерфейсе. Без этого пользователь не найдёт его в меню, хотя объект существует.
Второй частый пропуск — права. Новый объект не доступен никому, кроме ролей с полными правами. Откройте нужную роль в ветке Общие → Роли и выдайте права на документ: чтение, добавление, изменение, проведение, отмена проведения, интерактивные действия. Если документ в расширении, права выдают через роль расширения.
Нумерация
Свойства номера собраны на вкладке Нумерация:
| Свойство | Значения | Что даёт |
|---|---|---|
| Тип номера | Строка или Число | Строковый номер позволяет префиксы: ПТ00-000123 |
| Длина номера | например, 11 | Максимум символов в номере |
| Периодичность | Непрерывно, В пределах года, квартала, месяца, дня | Когда нумерация начинается заново |
| Автонумерация | флажок | Номер присваивается при первой записи |
| Контроль уникальности | флажок | Платформа не даст записать два документа с одинаковым номером в периоде |
Если несколько видов документов должны идти в одной сквозной нумерации, создайте в ветке Документы → Нумераторы общий нумератор и укажите его в свойстве Нумератор каждого документа.
Префикс номера задают в модуле объекта:
Процедура ПриУстановкеНовогоНомера(СтандартнаяОбработка, Префикс)
Префикс = "ПТ-";
КонецПроцедуры
Шапка и табличные части: какие данные хранит документ
У каждого документа уже есть стандартные реквизиты: Ссылка, Номер, Дата, Проведен, ПометкаУдаления. Создавать их не нужно. Свои данные добавляют на вкладке Данные.
Реквизиты шапки — значения, одинаковые для всего документа: склад, контрагент, организация, комментарий. Для каждого задают тип: ссылку на справочник, строку, число, дату.
Табличные части — строки однотипных данных: товары, услуги, сотрудники. У табличной части свои реквизиты: номенклатура, количество, цена, сумма. Номер строки НомерСтроки платформа ведёт сама.
Практичные настройки реквизитов:
- ✅ Проверка заполнения = Выдавать ошибку — платформа не даст провести документ с пустым полем. Код писать не надо.
- 🔢 Длина и точность числа: для количества хватит 15.3, для суммы — 15.2.
- 🧷 Связи параметров выбора — например, договор выбирается только по указанному контрагенту.
- 🔍 Индексировать — ставьте на реквизиты, по которым часто отбирают список.
💡 Не плодите реквизиты «на всякий случай». Каждый реквизит табличной части — это колонка в таблице базы данных, и лишние колонки замедляют запись больших документов.
Формы документа: интерфейс для пользователя
Формы создаются на вкладке Формы кнопкой с лупой — открывается конструктор формы. Обычно нужны три:
- Форма документа — для ввода и редактирования. Её основной реквизит
Объектимеет типДокументОбъект.ПриходТовара. - Форма списка — журнал документов этого вида с отбором и поиском.
- Форма выбора — когда документ выбирают в поле другого объекта.
Если форму не создать, платформа сгенерирует её автоматически. Для черновика это удобно, для работы пользователей — нет: в автоформе все реквизиты идут подряд без группировки.
В редакторе формы элементы перетаскивают из вкладки Реквизиты в дерево Элементы. Удобная раскладка для документа:
- шапка разбита на две колонки через группы с горизонтальной группировкой;
- табличная часть — на отдельной странице или занимает основную область;
- итоги (сумма, количество строк) — в подвале под таблицей;
- комментарий — внизу формы.
Не размещайте реквизиты, которые пользователь не должен менять, как обычные поля ввода. Для таких полей ставьте свойство ТолькоПросмотр или выводите их надписью.
Модуль формы: расчёты на клиенте и вызовы сервера
Модуль формы открывается на вкладке Модуль редактора формы. Код в нём делится директивами компиляции:
| Директива | Где выполняется | Доступ к данным формы |
|---|---|---|
&НаКлиенте | На компьютере пользователя | Да, но без запросов к базе |
&НаСервере | На сервере | Да, данные формы передаются на сервер |
&НаСервереБезКонтекста | На сервере | Нет, только параметры процедуры — самый лёгкий вызов |
Пересчёт суммы строки при изменении количества — типичный клиентский обработчик. Его создают в свойствах колонки табличной части, событие ПриИзменении:
&НаКлиенте
Процедура ТоварыКоличествоПриИзменении(Элемент)
ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
ТекущиеДанные.Сумма = ТекущиеДанные.Количество * ТекущиеДанные.Цена;
КонецПроцедуры
Подстановку цены из базы выносят на сервер без контекста — так на сервер не уходит вся форма:
&НаКлиенте
Процедура ТоварыНоменклатураПриИзменении(Элемент)
ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
ТекущиеДанные.Цена = ЦенаНоменклатуры(ТекущиеДанные.Номенклатура);
ТекущиеДанные.Сумма = ТекущиеДанные.Количество * ТекущиеДанные.Цена;
КонецПроцедуры
&НаСервереБезКонтекста
Функция ЦенаНоменклатуры(Номенклатура)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Цены.Цена КАК Цена
|ИЗ
| РегистрСведений.ЦеныНоменклатуры.СрезПоследних(, Номенклатура = &Номенклатура) КАК Цены";
Запрос.УстановитьПараметр("Номенклатура", Номенклатура);
Выборка = Запрос.Выполнить().Выбрать();
Возврат ?(Выборка.Следующий(), Выборка.Цена, 0);
КонецФункции
Значения по умолчанию для нового документа задают на сервере в ПриСозданииНаСервере. Проверяйте, что это новый объект, иначе обработчик перезапишет данные при каждом открытии:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Объект.Ссылка.Пустая() Тогда
Объект.Комментарий = "Создан " + Формат(ТекущаяДатаСеанса(), "ДЛФ=D");
КонецЕсли;
КонецПроцедуры
Модуль объекта: проведение и движения по регистрам
Чтобы документ мог проводиться, на вкладке Движения должны стоять:
Проведение— Разрешить;- в списке регистров — флажки на регистрах, по которым документ делает движения;
Удаление движений— обычно Удалять автоматически, чтобы при перепроведении старые записи стирались.
Кнопка Конструктор движений на той же вкладке генерирует заготовку обработчика ОбработкаПроведения: вы сопоставляете поля регистра с реквизитами документа, и код появляется в модуле объекта. Для простых документов этого хватает, для сложных — служит отправной точкой.
Минимальное проведение по регистру накопления остатков выглядит так:
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
Движения.ОстаткиТоваров.Записывать = Истина;
Для Каждого СтрокаТовара Из Товары Цикл
Движение = Движения.ОстаткиТоваров.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
Движение.Период = Дата;
Движение.Склад = Склад;
Движение.Номенклатура = СтрокаТовара.Номенклатура;
Движение.Количество = СтрокаТовара.Количество;
КонецЦикла;
КонецПроцедуры
Флаг Записывать = Истина говорит платформе записать набор движений после завершения обработчика. Без него движения не сохранятся.
Другие обработчики модуля объекта, которые нужны почти каждому документу:
- 🧩 ОбработкаПроверкиЗаполнения — сложные проверки, которые не задать флажком реквизита. Например, «количество в строке больше нуля». При ошибке ставят
Отказ = Истинаи выводят сообщение. - ✏️ ПередЗаписью — пересчёт итоговых реквизитов шапки перед записью. Параметр
РежимЗаписиподсказывает, записывают документ, проводят или отменяют проведение. - 📥 ОбработкаЗаполнения — заполнение при вводе на основании. Сами основания отмечают на вкладке
Ввод на основании.
Модуль объекта выполняется на сервере. Обращаться к элементам формы из него нельзя, только к реквизитам самого документа.
Оперативное проведение и управляемые блокировки
Свойство Оперативное проведение на вкладке Движения нужно, когда документ списывает остатки и важно не уйти в минус.
Если оно разрешено, при проведении документа текущей датой платформа передаёт в РежимПроведения значение Оперативный. Документ, датированный более ранней датой, проводится в режиме Неоперативный. Оперативно провести документ
будущей датой нельзя. В оперативном режиме контроль остатков проводят строго, в неоперативном — его часто смягчают, потому что это ретроспективное исправление учёта.
Чтобы два пользователя одновременно не списали один и тот же остаток, перед чтением остатков ставят управляемую блокировку. В свойствах корня конфигурации режим управления блокировкой данных должен быть Управляемый:
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.ОстаткиТоваров");
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
ЭлементБлокировки.УстановитьЗначение("Склад", Склад);
ЭлементБлокировки.ИсточникДанных = Товары;
ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Номенклатура", "Номенклатура");
Блокировка.Заблокировать();
Движения.ОстаткиТоваров.Записывать = Истина;
Для Каждого СтрокаТовара Из Товары Цикл
Движение = Движения.ОстаткиТоваров.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
Движение.Период = Дата;
Движение.Склад = Склад;
Движение.Номенклатура = СтрокаТовара.Номенклатура;
Движение.Количество = СтрокаТовара.Количество;
КонецЦикла;
Движения.Записать();
Если РежимПроведения = РежимПроведенияДокумента.Оперативный Тогда
ПроверитьОтрицательныеОстатки(Отказ);
КонецЕсли;
КонецПроцедуры
Блокировка снимается автоматически по окончании транзакции проведения. Блокируйте только то, что нужно: склад и номенклатуру из документа, а не весь регистр. Иначе пользователи на соседних складах будут ждать друг друга.
Процедура ПроверитьОтрицательныеОстатки — ваша: запросом к таблице остатков регистра по номенклатуре документа ищите строки с количеством меньше нуля и при находке ставьте Отказ = Истина. Порядок «записать движения, затем проверить остатки» удобнее старого «прочитать остатки, сравнить, записать»: проверка видит итог с учётом самого документа.
Создание и проведение документа из кода
Программно документ создают через менеджер. Код выполняется на сервере — в обработке, регламентном задании или общем модуле:
Документ = Документы.ПриходТовара.СоздатьДокумент();
Документ.Дата = ТекущаяДатаСеанса();
Документ.Склад = Склад;
СтрокаТовара = Документ.Товары.Добавить();
СтрокаТовара.Номенклатура = Номенклатура;
СтрокаТовара.Количество = 10;
СтрокаТовара.Цена = 150;
СтрокаТовара.Сумма = 1500;
Попытка
Документ.Записать(РежимЗаписиДокумента.Проведение);
Исключение
Сообщить("Документ не проведён: " + ОписаниеОшибки());
КонецПопытки;
Для существующего документа объект получают из ссылки: ДокументОбъект = Ссылка.ПолучитьОбъект(). Отмена проведения — Записать(РежимЗаписиДокумента.ОтменаПроведения).
💡 При массовом создании документов из обработки проводите каждый документ в своей попытке, как в примере. Тогда один документ с ошибкой не остановит всю загрузку, а в сообщениях останется список проблемных строк — их удобно разобрать и провести повторно.
Чтобы документ создавался кнопкой из формы другого объекта, не пишите свою команду: отметьте основание на вкладке Ввод на основании, заполните реквизиты в ОбработкаЗаполнения, и платформа сама добавит команду «Создать на основании».
Частые вопросы
Можно ли переименовать документ, когда в базе уже есть данные?
Ctrl+Shift+F) покажет все вхождения.