В процессе работы с 1С:Предприятие разработчики и аналитики часто сталкиваются с необходимостью определить, какой именно документ сформировал ту или иную запись в регистре. Это критично для отладки, анализа данных и построения отчетов. Основным инструментом для решения этой задачи служит системное свойство Ссылка, которое автоматически фиксирует связь между записью регистра и документом-источником.
Однако не все регистры в 1С одинаково устроены: в регистрах накопления и регистрах бухгалтерии свойство Ссылка ведет себя иначе, чем в регистрах сведений. Кроме того, существуют нюансы с виртуальными таблицами, транзакциями и программным доступом к этим данным. В этой статье мы подробно разберем механизмы работы свойства Ссылка, покажем практические примеры кода и предупредим о типичных ошибках.
Особое внимание уделим случаям, когда Ссылка может быть пустой или содержать неожиданные значения — например, при ручном внесении записей через Записать() или при обмене данными между базами. Также рассмотрим альтернативные способы определения документов-источников, когда стандартное свойство не работает.
Что такое свойство Ссылка в регистрах 1С
Свойство Ссылка — это встроенный механизм платформы 1С:Предприятие, который автоматически фиксирует ссылку на документ, сформировавший запись в регистре. Оно доступно во всех типах регистров, но его поведение зависит от:
- 📄 Типа регистра (накопления, сведений, бухгалтерии, расчета)
- 🔄 Способа записи (через документ, программно, обмен данными)
- 🔗 Настроек регистра (наличие измерения "Регистратор")
В большинстве случаев Ссылка совпадает с полем Регистратор, но это не всегда так. Например, в регистрах сведений без измерения "Регистратор" свойство Ссылка может оставаться пустым, даже если запись была создана документом. Важно понимать, что это свойство заполняется платформой автоматически только при записи через стандартные механизмы (например, метод Движения.Записать() в модуле документа).
Если запись в регистр добавляется в обход типового функционала (например, через прямой вызов Регистр.Записать()), свойство Ссылка не заполняется. Это частая причина ошибок при анализе данных.
Чтобы гарантированно получить документ-источник, используйте виртуальную таблицу ДвиженияДокумента вместо прямого обращения к регистру. Она всегда содержит корректную ссылку на документ, даже если в самом регистре Ссылка пустая.
Как работает Ссылка в регистрах накопления и бухгалтерии
В регистрах накопления и регистрах бухгалтерии свойство Ссылка тесно связано с измерением Регистратор. По умолчанию платформа 1С автоматически заполняет это поле при записи движений документом. Рассмотрим ключевые особенности:
- 🔗 Автоматическое заполнение: при вызове
Движения.Записать()в модуле документа платформа сама проставляетСсылка = СсылкаНаДокумент. - 📊 Виртуальные таблицы: в запросах к виртуальным таблицам (например,
РегистрНакопления.ОстаткиИОбороты) полеРегистраторвсегда доступно и совпадает соСсылкой. - ⚠️ Ручная запись: если запись добавляется через
Регистр.Записать()без указания регистратора,Ссылкаостанется пустой.
Пример кода для получения документа по записи регистра накопления:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| РегистрНакопления.ТоварыНаСкладах.Ссылка КАК Документ,
| РегистрНакопления.ТоварыНаСкладах.Номенклатура
|ИЗ
| РегистрНакопления.ТоварыНаСкладах КАК РегистрНакопления.ТоварыНаСкладах
|ГДЕ
| РегистрНакопления.ТоварыНаСкладах.Номенклатура = &Номенклатура";
Запрос.УстановитьПараметр("Номенклатура", СсылкаНаНоменклатуру);
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить("Документ: " + Выборка.Документ);
КонецЦикла;
⚠️ Внимание: В регистрах бухгалтерии полеСсылкаможет содержать ссылку на документ даже для ручных операций, если они были введены через типовой интерфейс (например, "Операция (бухгалтерский и налоговый учет)"). Однако при программном создании проводок без привязки к документуСсылкабудет пустой.
Особенности свойства Ссылка в регистрах сведений
В регистрах сведений логика работы свойства Ссылка отличается. Здесь все зависит от структуры регистра:
- 📌 С измерением "Регистратор": если регистр содержит измерение с типом "Документ" (обычно оно так и называется — "Регистратор"), то
Ссылкабудет совпадать с этим измерением. - 🚫 Без измерения "Регистратор": в этом случае
Ссылкане заполняется автоматически, даже если запись сделана документом. Чтобы отследить источник, придется использовать дополнительные механизмы (например, добавлять поле "ДокументИсточник" в ресурсы регистра). - 🔄 Периодические регистры: в периодических регистрах сведений
Ссылкаможет указывать на документ, только если запись была сделана через движения документа. При ручном редактировании (например, через форму списка) свойство останется пустым.
Пример структуры регистра сведений без измерения "Регистратор":
РегистрСведений КурсыВалют
{
Измерения:
Валюта (СправочникСсылка.Валюты);
Ресурсы:
Курс (Число, 10, 4);
Периодичность: День;
}
В таком регистре Ссылка всегда будет пустой, даже если запись добавлена документом "УстановкаКурсовВалют".
| Тип регистра | Наличие измерения "Регистратор" | Поведение свойства Ссылка |
|---|---|---|
| Регистр накопления | Да (по умолчанию) | Всегда заполняется ссылкой на документ |
| Регистр бухгалтерии | Да (обязательно) | Заполняется для проводок, созданных документами |
| Регистр сведений | Да | Заполняется только при записи через движения документа |
| Регистр сведений | Нет | Всегда пустое, независимо от способа записи |
Программное определение документа по записи регистра
Чтобы программно получить документ, сформировавший запись в регистре, можно использовать несколько подходов. Рассмотрим наиболее универсальные методы.
1. Через виртуальную таблицу ДвиженияДокумента
Это самый надежный способ, так как виртуальная таблица всегда содержит корректную привязку к документу:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ДвиженияДокумента.Ссылка КАК Документ,
| ДвиженияДокумента.Регистратор КАК Регистратор,
| ДвиженияДокумента.Период
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.ДвиженияДокумента(
| &ДатаНачала,
| &ДатаОкончания,
| Документ.ПоступлениеТоваровУслуг) КАК ДвиженияДокумента";
Запрос.УстановитьПараметр("ДатаНачала", НачалоДня(ТекущаяДата()));
Запрос.УстановитьПараметр("ДатаОкончания", КонецДня(ТекущаяДата()));
Результат = Запрос.Выполнить();
2. Через прямой запрос к регистру (если Ссылка заполнена)
Если вы уверены, что Ссылка заполнена (например, в регистре накопления), можно обратиться напрямую:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| РегистрНакопления.ТоварыНаСкладах.Ссылка КАК Документ
|ИЗ
| РегистрНакопления.ТоварыНаСкладах КАК РегистрНакопления.ТоварыНаСкладах
|ГДЕ
| РегистрНакопления.ТоварыНаСкладах.Номенклатура = &Номенклатура
| И РегистрНакопления.ТоварыНаСкладах.Ссылка <> ЗНАЧЕНИЕ(Ссылка.ПустаяСсылка)";
Запрос.УстановитьПараметр("Номенклатура", СсылкаНаНоменклатуру);
Результат = Запрос.Выполнить();
3. Через обход движений документа (если известен тип документа)
Если вы знаете, какой документ мог сформировать запись, можно перебрать его движения:
ДокументОбъект = Документы.ПоступлениеТоваровУслуг.НайтиПоНомеру("ПТ-000123");
Если Не ДокументОбъект.Пустая() Тогда
Движения = ДокументОбъект.ПолучитьДвижения();
Для Каждого Движение Из Движения.ТоварыНаСкладах Цикл
Сообщить("Номенклатура: " + Движение.Номенклатура +
", Количество: " + Движение.Количество +
", Документ: " + ДокументОбъект.Ссылка());
КонецЦикла;
КонецЕсли;
⚠️ Внимание: При работе с большими объемами данных запрос к виртуальной таблице ДвиженияДокумента может выполняться дольше, чем прямой запрос к регистру. Оптимизируйте запросы с помощью индексов и ограничений по датам.
Убедитесь, что запись в регистр делается через документ, а не программно|
Проверьте наличие измерения "Регистратор" в структуре регистра|
Используйте виртуальные таблицы для гарантированного получения документа|
Ограничивайте период выборки в запросах для ускорения работы|-->
Типичные ошибки и как их избежать
При работе со свойством Ссылка разработчики часто сталкиваются с типичными ошибками, которые приводят к некорректным данным или падениям производительности. Рассмотрим наиболее распространенные случаи.
1. Пустая ссылка при программной записи
Если вы добавляете запись в регистр через Регистр.Записать() без указания регистратора, Ссылка останется пустой. Решение:
- 🔧 Используйте
Движения.Записать()в модуле документа. - 📝 Если запись делается программно, явно укажите
Регистратор:
НоваяЗапись = РегистрыСведений.КурсыВалют.СоздатьНаборЗаписей();
НоваяЗапись.Отбор.Валюта.Установить(СсылкаНаВалюту);
НоваяЗапись.Отбор.Период.Установить(ТекущаяДата());
НоваяЗапись.Добавить();
НоваяЗапись.Записать(Истина, Документ.Ссылка); // Явно указываем регистратор
2. Несовпадение Ссылки и Регистратора в регистрах сведений
В регистрах сведений без измерения "Регистратор" свойство Ссылка не заполняется, даже если запись сделана документом. Решение:
- 📌 Добавьте измерение "Регистратор" типа "Документ".
- 🔄 Используйте дополнительное поле в ресурсах (например, "ДокументИсточник").
3. Ошибки при работе с виртуальными таблицами
При обращении к виртуальным таблицам (например, ДвиженияДокумента) важно учитывать:
- 🕒 Производительность: виртуальные таблицы могут тормозить на больших периодах. Всегда ограничивайте даты.
- 🔍 Фильтрация: если не указать тип документа в параметрах виртуальной таблицы, запрос будет сканировать движения всех документов.
Пример неправильного запроса (долго выполняется):
// ПЛОХО: нет ограничения по типу документа и датам
Запрос.Текст = "ВЫБРАТЬ Ссылка ИЗ РегистрНакопления.ТоварыНаСкладах.ДвиженияДокумента";
Пример правильного запроса:
// ХОРОШО: ограничение по датам и типу документа
Запрос.Текст = "ВЫБРАТЬ Ссылка ИЗ РегистрНакопления.ТоварыНаСкладах.ДвиженияДокумента(
&ДатаНачала, &ДатаОкончания, Документ.ПоступлениеТоваровУслуг)";
⚠️ Внимание: В некоторых конфигурациях (например, 1С:ERP или 1С:КА) структуры регистров могут отличаться от типовой 1С:Бухгалтерии. Всегда проверяйте наличие измерения "Регистратор" в метаданных перед написанием кода.
Альтернативные способы определения документа-источника
Если свойство Ссылка по какой-то причине не доступно или пустое, можно использовать альтернативные методы для определения документа, сформировавшего запись.
1. Через журнал регистрации
В 1С:Предприятие ведется журнал регистрации, который фиксирует все изменения данных. Через него можно отследить, какой документ и когда изменил запись в регистре:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЖурналРегистрации.ДанныеКлюч.Ссылка КАК Документ,
| ЖурналРегистрации.ДатаВремя
|ИЗ
| РегистрСведений.ЖурналРегистрации КАК ЖурналРегистрации
|ГДЕ
| ЖурналРегистрации.МETAДАННЫЕ.Имя = ""КурсыВалют""
| И ЖурналРегистрации.ДанныеКлюч.Валюта = &Валюта";
Запрос.УстановитьПараметр("Валюта", СсылкаНаВалюту);
Результат = Запрос.Выполнить();
2. Через механизм подчиненности
Если запись в регистре подчинена документу (например, через реквизит "Владелец"), можно использовать этот реквизит для определения источника:
ЗаписьРегистра = РегистрыСведений.КурсыВалют.ПолучитьПоследнююЗапись(СсылкаНаВалюту);
Если Не ЗаписьРегистра.Пустая() Тогда
Документ = ЗаписьРегистра.Владелец; // Если есть реквизит "Владелец"
КонецЕсли;
3. Через анализ движений всех документов за период
Если другие методы не сработали, можно перебрать движения всех документов за интересующий период и сравнить данные:
ДатаНачала = НачалоДня(ТекущаяДата());
ДатаОкончания = КонецДня(ТекущаяДата());
// Получаем все документы, которые могли сформировать запись
Документы = Документы.ПоступлениеТоваровУслуг.ВыбратьПоПериоду(ДатаНачала, ДатаОкончания);
Пока Документы.Следующий() Цикл
Движения = Документы.ТекущийДокумент().ПолучитьДвижения();
Для Каждого Движение Из Движения.ТоварыНаСкладах Цикл
Если Движение.Номенклатура = СсылкаНаНоменклатуру Тогда
Сообщить("Найден документ: " + Документы.ТекущийДокумент().Ссылка());
КонецЕсли;
КонецЦикла;
КонецЦикла;
Этот метод самый ресурсоемкий, но гарантированно работает в любых случаях.
Что делать, если документ удален?
Если документ, сформировавший запись в регистре, был удален, свойство Ссылка будет содержать "битую" ссылку (например, Документ.ПоступлениеТоваровУслуг:00000000-...). В этом случае:
1. Проверьте журнал регистрации на наличие информации об удалении.
2. Используйте архивные копии базы (если ведется архивация).
3. Восстановите документ по резервной копии, если это критично для бизнес-процессов.
Практические примеры и кейсы
Рассмотрим реальные сценарии, в которых определение документа по записи регистра помогает решить бизнес-задачи.
Кейс 1: Поиск документа, изменившего остаток товара
Задача: найти, какой документ последним изменил остаток номенклатуры "Монитор Samsung 24"" на складе "Основной".
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| ДвиженияДокумента.Ссылка КАК Документ,
| ДвиженияДокумента.Период КАК Дата
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.ДвиженияДокумента(
| ДатаНачала(&ДатаНачала, День),
| &ДатаОкончания,
| Документ.ПоступлениеТоваровУслуг,
| Документ.РеализацияТоваровУслуг) КАК ДвиженияДокумента
|ГДЕ
| ДвиженияДокумента.Номенклатура = &Номенклатура
| И ДвиженияДокумента.Склад = &Склад
|УПОРЯДОЧИТЬ ПО
| ДвиженияДокумента.Период УБЫВ";
Запрос.УстановитьПараметр("ДатаНачала", НачалоДня(ТекущаяДата() - 30)); // Ищем за последний месяц
Запрос.УстановитьПараметр("ДатаОкончания", КонецДня(ТекущаяДата()));
Запрос.УстановитьПараметр("Номенклатура", СсылкаНаНоменклатуру);
Запрос.УстановитьПараметр("Склад", СсылкаНаСклад);
Результат = Запрос.Выполнить();
Если Результат.Пустой() Тогда
Сообщить("Движения не найдены!");
Иначе
Выборка = Результат.Выбрать();
Выборка.Следующий();
Сообщить("Последний документ: " + Выборка.Документ + ", дата: " + Выборка.Дата);
КонецЕсли;
Кейс 2: Проверка корректности курсов валют
Задача: проверить, какие документы устанавливали курс доллара за последний месяц, и выявить расхождения.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ДвиженияДокумента.Ссылка КАК Документ,
| ДвиженияДокумента.Период КАК Дата,
| ДвиженияДокумента.Курс КАК Курс
|ИЗ
| РегистрСведений.КурсыВалют.ДвиженияДокумента(
| ДатаНачала(&ДатаНачала, Месяц),
| &ДатаОкончания,
| Документ.УстановкаКурсовВалют) КАК ДвиженияДокумента
|ГДЕ
| ДвиженияДокумента.Валюта = &Валюта
|УПОРЯДОЧИТЬ ПО
| ДвиженияДокумента.Период";
Запрос.УстановитьПараметр("ДатаНачала", НачалоМесяца(ТекущаяДата()));
Запрос.УстановитьПараметр("ДатаОкончания", КонецДня(ТекущаяДата()));
Запрос.УстановитьПараметр("Валюта", СсылкаНаВалютуUSD);
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить(Строка(Выборка.Дата) + ": " + Выборка.Документ + ", курс = " + Выборка.Курс);
КонецЦикла;
Кейс 3: Анализ изменений в регистре сведений без измерения "Регистратор"
Задача: в регистре сведений "ЦеныНоменклатуры" нет измерения "Регистратор", но нужно отследить, какой документ последним изменил цену товара.
Решение: добавить в регистр ресурс "ДокументИсточник" и заполнять его при записи:
// В модуле документа "УстановкаЦенНоменклатуры"
Процедура ОбработкаПроведения(Отказ, Режим)
Движения.ЦеныНоменклатуры.Записать();
// Дополнительно записываем документ-источник в регистр
НаборЗаписей = РегистрыСведений.ЦеныНоменклатуры.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Номенклатура.Установить(ЭтотОбъект.Номенклатура);
НаборЗаписей.Отбор.Период.Установить(ЭтотОбъект.Дата);
НаборЗаписей.Прочитать();
Если Не НаборЗаписей.Пустой() Тогда
Запись = НаборЗаписей[0];
Запись.ДокументИсточник = ЭтотОбъект.Ссылка();
НаборЗаписей.Записать();
КонецЕсли;
КонецПроцедуры;
Теперь документ-источник всегда можно получить через ресурс ДокументИсточник.
Если в регистре сведений нет измерения "Регистратор", единственный надежный способ отследить документ-источник — добавить дополнительное поле (ресурс или реквизит) и заполнять его вручную при записи.
FAQ: Частые вопросы по работе со свойством Ссылка
Можно ли изменить значение свойства Ссылка после записи?
Нет, свойство Ссылка заполняется платформой 1С автоматически при записи и не предназначено для ручного изменения. Если вам нужно хранить дополнительную информацию о источнике записи, добавьте отдельное поле в регистр (например, реквизит "ДокументИсточник").
Почему в регистре сведений свойство Ссылка пустое, хотя запись сделана документом?
Скорее всего, в вашем регистре сведений отсутствует измерение "Регистратор" типа "Документ". Без этого измерения платформа не заполняет Ссылка автоматически. Решения:
- Добавьте измерение "Регистратор" в структуру регистра.
- Используйте виртуальную таблицу
ДвиженияДокументадля получения документа. - Добавьте ресурс "ДокументИсточник" и заполняйте его вручную.
Как получить документ по записи регистра бухгалтерии?
В регистрах бухгалтерии свойство Ссылка совпадает с полем Регистратор и указывает на документ, сформировавший проводку. Пример запроса:
Запрос.Текст = "ВЫБРАТЬ
| РегистрБухгалтерии.Хозрасчетный.Ссылка КАК Документ,
| РегистрБухгалтерии.Хозрасчетный.СчетДт,
| РегистрБухгалтерии.Хозрасчетный.Сумма
|ИЗ
| РегистрБухгалтерии.Хозрасчетный КАК РегистрБухгалтерии.Хозрасчетный
|ГДЕ
| РегистрБухгалтерии.Хозрасчетный.СчетДт = &Счет";
Для проводок, созданных вручную (например, через документ "Операция"), Ссылка будет содержать ссылку на этот документ.
Можно ли по записи в регистре определить пользователя, который создал документ?
Нет, свойство Ссылка содержит только ссылку на документ, но не на пользователя. Чтобы получить информацию о пользователе, нужно:
- Получить документ по
Ссылке. - Обратиться к реквизиту документа "Ответственный" или "Пользователь".
- Или использовать журнал регистрации, где фиксируется пользователь, изменивший данные.
Пример:
ДокументОбъект = Запрос.Ссылка.ПолучитьОбъект();
Сообщить("Пользователь: " + ДокументОбъект.Пользователь());
Как оптимизировать запрос для поиска документа по большому регистру?
При работе с большими регистрами (например, с миллионами записей) используйте следующие приемы:
- 📅 Ограничи