Работа с реквизитами чужих документов в 1С:Предприятие — одна из самых частых задач при разработке конфигураций, написании отчётов или обработок. Новичков часто ставит в тупик вопрос: как безопасно и корректно получить значение поля из документа, который не является текущим? Ошибки здесь чреваты не только падением кода, но и искажением данных, особенно если речь идёт о связанных документах (например, счёт на оплату и реализация товаров).
В этой статье разберём все актуальные способы обращения к реквизитам других документов — от простейшего получения через ссылку до сложных запросов с joins. Особое внимание уделим нюансам работы с удалёнными документами и транзакциями, которые часто становятся источником багов. Материал будет полезен как начинающим программистам 1С, так и опытным разработчикам, которые хотят систематизировать знания.
1. Прямое обращение через ссылку на документ
Самый очевидный и простой способ — получить ссылку на документ и обратиться к его реквизиту напрямую. Этот метод работает, если у вас уже есть ссылка (например, из поля СсылкаНаДокумент в текущем объекте) или вы можете её получить через стандартные механизмы платформы.
Пример кода для получения номера документа "Заказ покупателя" по его ссылке:
СсылкаНаЗаказ = Документы.ЗаказПокупателя.НайтиПоНомеру("000000001", Дата);
Если Не СсылкаНаЗаказ.Пустая() Тогда
НомерЗаказа = СсылкаНаЗаказ.Номер;
Сообщить("Номер заказа: " + НомерЗаказа);
КонецЕсли;
- ✅ Плюсы: максимальная простота, минимальный код.
- ⚠️ Минусы: требует загрузки объекта в память (может быть медленно для больших документов).
- 🔄 Когда использовать: для разовых операций с небольшим количеством документов.
⚠️ Внимание: Если документ ещё не проведён или удалён, прямое обращение вызовет ошибку. Всегда проверяйте существование объекта через методПустая()илиЭтоГруппа()(для справочников).
2. Использование метода ПолучитьОбъект()
Если у вас есть только уникальный идентификатор документа (например, из внешней системы), но нет ссылки, можно воспользоваться методом ПолучитьОбъект(). Он возвращает объект документа по его GUID или другому идентификатору.
Пример для работы с УникальнымИдентификатором:
УидДокумента = "a1b2c3d4-5678-90ef-1234-567890abcdef";
ДокументОбъект = Документы.РеализацияТоваровУслуг.ПолучитьОбъект(УидДокумента);
Если ДокументОбъект <> Неопределён Тогда
ДатаДокумента = ДокументОбъект.Дата;
КонецЕсли;
Этот метод удобен при интеграции с внешними системами, где передаются именно идентификаторы, а не ссылки. Однако он имеет ограничения:
- 🔍 Работает только для существующих документов (иначе вернёт
Неопределён). - 🚫 Не подходит для удалённых или помеченных на удаление документов.
- ⚡ Может быть медленнее, чем работа со ссылками, из-за внутренних проверок.
Для ускорения работы с ПолучитьОбъект() предварительно проверьте наличие документа через запрос к базе — это сэкономит ресурсы, если объект не существует.
3. Работа через запросы (SELECT)
Самый универсальный и безопасный способ — использование запросов на языке 1С. Он позволяет получить реквизиты документов без их загрузки в память, что критично для производительности при работе с большими объёмами данных.
Базовый пример запроса для получения даты и суммы документа "Поступление товаров":
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПоступлениеТоваровУслуг.Ссылка КАК Ссылка,
| ПоступлениеТоваровУслуг.Дата КАК Дата,
| ПоступлениеТоваровУслуг.СуммаДокумента КАК Сумма
|ИЗ
| Документ.ПоступлениеТоваровУслуг КАК ПоступлениеТоваровУслуг
|ГДЕ
| ПоступлениеТоваровУслуг.Номер = &Номер";
Запрос.УстановитьПараметр("Номер", "000000005");
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Если Выборка.Следующий() Тогда
Сообщить("Дата: " + Выборка.Дата + ", Сумма: " + Выборка.Сумма);
КонецЕсли;
Преимущества этого метода:
- 📊 Можно получить данные многих документов за один запрос.
- 🔒 Безопасно для удалённых или непроведённых документов (не вызовет ошибку).
- ⚡ Оптимизировано для работы с большими базами (не грузит объекты в память).
⚠️ Внимание: В запросах нельзя напрямую обращаться к реквизитам объектов, которые не включены в выборку. Например, если вы выбрали толькоСсылка, тоВыборка.Ссылка.Номерработать не будет — нужно явно указывать все нужные поля вВЫБРАТЬ.
| Метод | Скорость | Безопасность | Когда использовать |
|---|---|---|---|
| Прямое обращение | ⚡ Быстро (для 1 документа) | ❌ Риск ошибок | Разовые операции |
ПолучитьОбъект() |
🐢 Медленно | ⚠️ Требует проверок | Интеграция по UID |
| Запросы | ⚡⚡ Очень быстро | ✅ Максимальная | Массовая обработка |
4. Обращение к реквизитам через МенеджерЗначений
Если вам нужно получить значение реквизита без загрузки всего документа, можно использовать МенеджерЗначений. Этот метод полезен, когда документ большой, а нужен только один реквизит.
Пример для получения контрагента из документа "Счёт на оплату":
СсылкаНаСчёт = Документы.СчётНаОплату.НайтиПоНомеру("СЧ-0001", ТекущаяДата());
Менеджер = Новый МенеджерЗначения(СсылкаНаСчёт);
Контрагент = Менеджер.Получить("Контрагент");
Сообщить("Контрагент: " + Контрагент.Наименование);
МенеджерЗначений удобен в следующих случаях:
- 📄 Нужно получить один-два реквизита из большого документа.
- 🔄 Документ часто изменяется, и вы не хотите блокировать его на чтение.
- 🛠️ Работаете с динамическими реквизитами (которые могут отсутствовать).
Что делать, если МенеджерЗначений возвращает Неопределён?
Это означает, что реквизит не существует в документе или документ не найден. Проверьте:
1. Правильность ссылки на документ.
2. Наличие реквизита в метаданных (возможно, опечатка в имени).
3. Права доступа текущего пользователя к документу.
5. Работа с реквизитами в транзакциях
Один из самых коварных моментов — обращение к реквизитам документов внутри транзакций. Если вы изменяете документ в транзакции, а затем пытаетесь прочитать его реквизиты, можно получить неактуальные данные или ошибку блокировки.
Пример проблемного кода:
НачатьТранзакцию();
Док = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
Док.Контрагент = Справочники.Контрагенты.НайтиПоНаименованию("ООО Ромашка");
Док.Записать();
// ❌ ОШИБКА: пытаемся прочитать несохранённый документ
Сумма = Док.СуммаДокумента; // Может вернуть 0 или неактуальное значение
ЗафиксироватьТранзакцию();
Как правильно:
- 🔄 Читать реквизиты ДО начала транзакции (если они не меняются).
- 🔒 Использовать уровни изоляции транзакций (например,
УстановитьУровеньИзоляции(УровеньИзоляцииТранзакций.ПовторяемоеЧтение)). - 📊 Для критичных операций — читать данные через запрос с указанием
ДЛЯ ИЗМЕНЕНИЯ.
⚠️ Внимание: В 1С:Предприятие 8.3.20+ изменилось поведение транзакций при работе с реквизитами документов. Если вы используете старые версии, тестируйте код на блокировки в многопользовательском режиме.
Убедиться, что документ существует (не Пустая())
Проверить права доступа текущего пользователя
Оценить необходимость транзакции
Подумать о производительности (запрос vs прямое обращение)-->
6. Особенности работы с удалёнными и непроведёнными документами
Документы в 1С могут находиться в разных состояниях: проведённые, непроведённые, помеченные на удаление или удалённые. Каждое состояние требует своего подхода.
Как обращаться к реквизитам в зависимости от состояния:
| Состояние документа | Метод обращения | Риски |
|---|---|---|
| Проведённый | Любой (прямое обращение, запросы, менеджер) | ✅ Без рисков |
| Непроведённый | Прямое обращение или менеджер | ⚠️ Движения не сформированы |
| Помечен на удаление | Только через запросы с ПометкаУдаления = Ложь |
❌ Ошибка при прямом обращении |
| Удалённый | Только архивные запросы | ❌ Данные могут быть неполными |
Пример безопасного запроса для помеченных на удаление документов:
Запрос.Текст =
"ВЫБРАТЬ
| ЗаказПокупателя.Ссылка КАК Ссылка,
| ЗаказПокупателя.Дата КАК Дата
|ИЗ
| Документ.ЗаказПокупателя КАК ЗаказПокупателя
|ГДЕ
| ЗаказПокупателя.ПометкаУдаления = Ложь
| И ЗаказПокупателя.Номер = &Номер";
Всегда проверяйте состояние документа перед работой с его реквизитами. Для помеченных на удаление документов используйте фильтр ПометкаУдаления = Ложь в запросах.
7. Оптимизация производительности при массовой обработке
Если вам нужно обработать реквизиты тысяч документов, прямой перебор через ПолучитьОбъект() или Ссылка.Реквизит приведёт к тормозам. В таких случаях используйте:
- 📊 Пакетные запросы с ограничением по 100–500 документов за раз.
- 🔄 Временные таблицы для промежуточных данных.
- ⚡ Асинхронные операции (для фоновых задач).
- 🗃️ Кэширование часто используемых реквизитов (например, в
Соответствие).
Пример оптимизированного запроса для массового чтения:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 500
| Реализация.Ссылка КАК Ссылка,
| Реализация.Контрагент КАК Контрагент,
| Реализация.СуммаДокумента КАК Сумма
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Реализация
|ГДЕ
| Реализация.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания";
Запрос.УстановитьПараметр("ДатаНачала", НачалоМесяца(ТекущаяДата()));
Запрос.УстановитьПараметр("ДатаОкончания", КонецМесяца(ТекущаяДата()));
Результат = Запрос.Выполнить();
Для ещё большей производительности можно использовать планы обмена или регламентные задания, если обработка не требует мгновенного результата.
FAQ: Частые вопросы по работе с реквизитами документов
Можно ли получить реквизит документа, который ещё не записан?
Нет, до записи документ существует только в памяти и не имеет устойчивой ссылки. Если вам нужно работать с временными данными, используйте Структуру или ТаблицуЗначений для хранения промежуточных значений.
Как получить реквизит документа из другой базы (распределённой информационной системы)?
Для этого используйте планы обмена или веб-сервисы. Пример через план обмена:
УзелОбмена = ПланыОбмена.ОсновнойПланОбмена.НайтиУзелПоИмени("Склад");
Данные = УзелОбмена.ПолучитьДанные();
Документ = Данные.ПолучитьДокумент("РеализацияТоваровУслуг", УидДокумента);
Убедитесь, что у вас настроены права доступа и синхронизация между базами.
Почему при обращении к реквизиту вылетает ошибка "Объект не найден"?
Причины могут быть следующие:
- Документ удалён или помечен на удаление.
- Не хватает прав доступа у текущего пользователя.
- Ссылка на документ некорректна (например, из другой базы).
- Реквизит удален из конфигурации или переименован.
Проверьте существование документа через Ссылка.Пустая() и права пользователя.
Как получить реквизит документа, если известен только его номер?
Используйте метод НайтиПоНомеру():
Ссылка = Документы.ЗаказПокупателя.НайтиПоНомеру("000000010", ТекущаяДата());
Если Не Ссылка.Пустая() Тогда
Контрагент = Ссылка.Контрагент;
КонецЕсли;
Обратите внимание, что номер должен быть уникальным в пределах периода (месяца, года — в зависимости от настроек нумерации).
Можно ли изменить реквизит чужого документа напрямую?
Технически — да, но это крайне не рекомендуется. Изменение документов в обход бизнес-логики может привести к:
- 🔄 Нарушению последовательности проводок.
- 📊 Рассинхронизации итогов и регистров.
- 🚫 Ошибкам при проверке связей документов.
Используйте стандартные методы Записать() и Провести() или создавайте отдельные документы корректировки.