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