Присвоение значения реквизиту в 1С 8.3: объект, табличная часть, константа, регистр и форма

· 9 мин

Содержание

Чтобы присвоить значение реквизиту в 1С, нужен объект, а не ссылка: Объект = Ссылка.ПолучитьОбъект(); Объект.Комментарий = "Текст"; Объект.Записать();. Внутри модуля самого объекта реквизит доступен прямо по имени: Комментарий = "Текст";. Без вызова Записать() новое значение живёт только в памяти и в базу не попадёт.

Способ зависит от того, где хранится значение. Реквизит справочника или документа меняют через объект, строку табличной части — через коллекцию строк, константу — методом Установить(), запись регистра сведений — через менеджер записи или набор записей. На форме работают с реквизитом формы Объект и не трогают базу до нажатия «Записать».

Что меняемКак присваиваемКак сохраняем
Реквизит справочника/документаОбъект.Реквизит = ЗначениеОбъект.Записать()
Строка табличной частиСтрока.Колонка = ЗначениеЗаписью владельца
КонстантаКонстанты.Имя.Установить(Значение)Сразу при вызове
Регистр сведенийМенеджерЗаписи.Ресурс = ЗначениеМенеджерЗаписи.Записать()
Реквизит на формеОбъект.Реквизит = ЗначениеПользователь записывает форму

Базовое присваивание значения реквизиту в модуле объекта

Оператор присваивания во встроенном языке один — знак =. Слева стоит реквизит, справа выражение. Точка с запятой в конце обязательна.

В модуле объекта (документа, справочника, обработки) реквизиты видны как переменные. Префикс ЭтотОбъект. можно писать, а можно опускать:

Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)

    Комментарий = "Создан автоматически";
    ЭтотОбъект.Ответственный = Пользователи.ТекущийПользователь();
    СуммаДокумента = Товары.Итог("Сумма");

КонецПроцедуры

В обработчике ПередЗаписью вызывать Записать() не нужно: платформа и так пишет объект после обработчика. Повторный вызов внутри него приведёт к рекурсии.

Пользователи.ТекущийПользователь() — функция Библиотеки стандартных подсистем. Если её в конфигурации нет, текущего пользователя получают иначе, например через параметр сеанса, принятый в вашей конфигурации.

Где удобно присваивать значения в модуле объекта:

  • 📝 ОбработкаЗаполнения — начальные значения при создании нового документа или при вводе на основании;
  • 🧮 ПередЗаписью — расчётные реквизиты: итоговая сумма, номер версии, дата изменения;
  • ✅ ОбработкаПроверкиЗаполнения — не присваивание, а проверка, о ней ниже.

Пример начального заполнения нового документа:

Процедура ОбработкаЗаполнения(ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка)
    Если Не ЗначениеЗаполнено(Дата) Тогда
        Дата = ТекущаяДатаСеанса();
    КонецЕсли;
    Если ТипЗнч(ДанныеЗаполнения) = Тип("Структура") Тогда
        ЗаполнитьЗначенияСвойств(ЭтотОбъект, ДанныеЗаполнения);
    КонецЕсли;
КонецПроцедуры

Проверка ЗначениеЗаполнено здесь защищает от затирания даты, которую уже передали при создании документа.

Как присвоить реквизиту значение из другого модуля и записать объект

Чаще всего значение меняют «снаружи»: из общего модуля, обработки, регламентного задания. Тогда порядок такой:

  1. Получите ссылку на элемент — из запроса, поиском или из параметра.
  2. Вызовите ПолучитьОбъект(). Метод работает только на сервере.
  3. Присвойте значения реквизитам объекта.
  4. Вызовите Записать(). Для документа можно указать режим записи.
&НаСервере
Процедура УстановитьКомментарий(ДокументСсылка, Текст)

    ДокОбъект = ДокументСсылка.ПолучитьОбъект();
    ДокОбъект.Комментарий = Текст;
    ДокОбъект.Записать(РежимЗаписиДокумента.Запись);

КонецПроцедуры

Если документ проведён и от изменённого реквизита зависят движения (сумма, склад, счёт), записывайте его в режиме РежимЗаписиДокумента.Проведение. Иначе реквизит в шапке изменится, а движения в регистрах останутся старыми, и отчёты разойдутся с документом. Для реквизитов вроде комментария или ответственного достаточно обычной записи.

Самая частая ошибка новичка — присвоить значение реквизиту ссылки:

ДокументСсылка.Комментарий = "Текст"; // ошибка

Ссылка в 1С только читает данные. Платформа ответит Поле объекта недоступно для записи. Нужен именно объект.

Массовое изменение через ПолучитьОбъект() + Записать() запускает все подписки на события, проверки и перепроведение. На тысяче документов это долго и может поменять движения. Перед групповой обработкой сделайте резервную копию базы.

Если нужно переписать реквизит без бизнес-логики (например, при загрузке данных из другой базы), используют режим обмена:

ДокОбъект.ОбменДанными.Загрузка = Истина;
ДокОбъект.Записать();

В этом режиме не выполняются проверки заполнения и большая часть кода обработчиков, которые проверяют этот флаг. Применяйте его осознанно: ошибочные данные тоже запишутся.

Табличные части и коллекции значений: присваивание по строкам

Реквизит табличной части принадлежит конкретной строке. Сначала получаете строку, потом присваиваете.

Новая строка:

НоваяСтрока = ДокОбъект.Товары.Добавить();
НоваяСтрока.Номенклатура = НоменклатураСсылка;
НоваяСтрока.Количество   = 10;
НоваяСтрока.Цена         = 150;
НоваяСтрока.Сумма        = НоваяСтрока.Количество * НоваяСтрока.Цена; // 1500

Все существующие строки — в цикле:

Для Каждого СтрокаТЧ Из ДокОбъект.Товары Цикл
    СтрокаТЧ.Сумма = СтрокаТЧ.Количество * СтрокаТЧ.Цена;
КонецЦикла;

Строка по номеру: индекс начинается с нуля. ДокОбъект.Товары[0].Цена = 200; меняет первую строку. Обращение к несуществующему индексу вызовет ошибку, поэтому сначала проверьте Количество().

Поиск строки по значению:

Найденные = ДокОбъект.Товары.НайтиСтроки(Новый Структура("Номенклатура", НоменклатураСсылка));
Для Каждого СтрокаТЧ Из Найденные Цикл
    СтрокаТЧ.Цена = 180;
КонецЦикла;

Изменения табличной части сохраняются вместе с объектом. Отдельного Записать() у неё нет.

Для коллекций в памяти — таблицы значений, структуры, соответствия — правила похожи, но писать в базу ничего не нужно:

КоллекцияКак присвоить
Таблица значенийСтрока.Колонка = Значение или ТЗ.ЗаполнитьЗначения(0, "Скидка")
СтруктураСтруктура.Вставить("Ключ", Значение) или Структура.Ключ = Значение для существующего ключа
СоответствиеСоответствие.Вставить(Ключ, Значение)
МассивМассив[0] = Значение или Массив.Добавить(Значение)

Когда нужно перенести сразу много полей с одинаковыми именами, выручает ЗаполнитьЗначенияСвойств:

ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаИсточник);
ЗаполнитьЗначенияСвойств(ДокОбъект, ДанныеЗаполнения, "Организация, Контрагент");

Второй параметр — откуда берём, третий — список свойств через запятую. Четвёртый параметр — исключения: какие свойства не копировать. Он пригодится, когда у источника и приёмника совпадают служебные поля вроде Номер, Дата или Ответственный, а переносить их не нужно.

Константы и регистры сведений: где значение хранится отдельно от объекта

Константа

Константа хранит одно значение на всю базу. Присвоить его проще всего методом Установить(). Запись происходит сразу, без отдельного Записать():

Константы.ИспользоватьВалютныйУчет.Установить(Истина);
Значение = Константы.ИспользоватьВалютныйУчет.Получить();

Имя константы бывает другим — смотрите ветку Константы в дереве конфигурации. Второй способ — менеджер значения. Он нужен, если важно, чтобы сработали обработчики ПередЗаписью и ПриЗаписи модуля менеджера значения константы:

МенеджерЗначения = Константы.ИспользоватьВалютныйУчет.СоздатьМенеджерЗначения();
МенеджерЗначения.Значение = Истина;
МенеджерЗначения.Записать();

Функциональные опции часто построены на константах. После изменения такой константы интерфейс у пользователей обновится не сразу, а после перезапуска сеанса или обновления повторно используемых значений.

Регистр сведений

Здесь значение хранится не в одном поле, а в записи, которая определяется измерениями (и периодом, если регистр периодический). Для одной записи удобен менеджер записи:

МенеджерЗаписи = РегистрыСведений.КурсыВалют.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Период    = НачалоДня(ТекущаяДатаСеанса());
МенеджерЗаписи.Валюта    = ВалютаСсылка;
МенеджерЗаписи.Курс      = 92.5;
МенеджерЗаписи.Кратность = 1;
МенеджерЗаписи.Записать();

Если запись с таким периодом и измерениями уже есть, Записать() её заменит: параметр замещения по умолчанию равен Истина.

Для нескольких записей сразу используют набор записей с отбором:

Набор = РегистрыСведений.КурсыВалют.СоздатьНаборЗаписей();
Набор.Отбор.Валюта.Установить(ВалютаСсылка);
Набор.Прочитать();
Для Каждого Запись Из Набор Цикл
    Запись.Кратность = 1;
КонецЦикла;
Набор.Записать();

Набор без отбора при записи заменит весь регистр. Если вызвать Записать() у пустого набора без установленного отбора, все записи регистра будут удалены. Всегда ставьте отбор перед записью.

Регистр, подчинённый регистратору, напрямую так не пишут: его записи формирует документ при проведении. Значение там меняют через сам документ.

Присвоение значения реквизиту на форме

На управляемой форме данные объекта лежат в основном реквизите формы, обычно он называется Объект. Присваивание на клиенте меняет только форму, в базу ничего не пишется, пока пользователь не нажмёт «Записать»:

&НаКлиенте
Процедура КонтрагентПриИзменении(Элемент)
    Объект.Договор = Неопределено;
    Объект.Комментарий = "Контрагент изменён";
    Модифицированность = Истина;
КонецПроцедуры

Флаг Модифицированность нужен, чтобы форма при закрытии спросила о сохранении. При программном изменении данных он не всегда ставится сам.

Свои реквизиты формы (не из Объект) присваиваются по имени: ПериодОтчета = ТекущаяДата(); — на клиенте или на сервере, без разницы.

На сервере формы иногда нужно поработать с настоящим объектом: вызвать его экспортный метод. Тогда используют пару функций:

&НаСервере
Процедура ПересчитатьНаСервере()
    ДокОбъект = РеквизитФормыВЗначение("Объект");
    ДокОбъект.ПересчитатьСуммы(); // экспортная процедура модуля объекта
    ЗначениеВРеквизитФормы(ДокОбъект, "Объект");
КонецПроцедуры

Управление интерфейсом — это тоже присваивание, только свойствам элементов, а не данных:

  • 👁 Элементы.Договор.Видимость = Ложь; — скрыть поле;
  • 🔒 Элементы.Договор.ТолькоПросмотр = Истина; — запретить ввод;
  • 🚫 Элементы.Договор.Доступность = Ложь; — сделать поле серым.

Обратите внимание на разницу: Объект.Договор — данные, Элементы.Договор — поле на экране. Перепутать их — классическая причина ошибки Поле объекта не обнаружено.

Ссылочные и составные типы: что можно положить в реквизит

Реквизит ссылочного типа ждёт ссылку, а не строку с наименованием. Типичные способы получить нужное значение:

  • 🔎 Справочники.Валюты.НайтиПоКоду("643") — поиск по коду;
  • 🔎 Справочники.Контрагенты.НайтиПоНаименованию("Ромашка", Истина) — точное совпадение;
  • 📌 Справочники.ЕдиницыИзмерения.Штука — предопределённый элемент (имя смотрите в конфигурации);
  • 📌 Перечисления.ВидыОпераций.Поступление — значение перечисления на сервере;
  • 💻 ПредопределенноеЗначение("Перечисление.ВидыОпераций.Поступление") — то же на клиенте;
  • ⭕ Справочники.Контрагенты.ПустаяСсылка() — очистить реквизит.

НайтиПоКоду и НайтиПоНаименованию при неудаче возвращают пустую ссылку, а не Неопределено. Проверяйте результат через ЗначениеЗаполнено():

Валюта = Справочники.Валюты.НайтиПоКоду("840");
Если Не ЗначениеЗаполнено(Валюта) Тогда
    ВызватьИсключение "Валюта с кодом 840 не найдена";
КонецЕсли;
ДокОбъект.ВалютаДокумента = Валюта;

Составной тип — реквизит, который может хранить значения разных типов. Например, «Контрагент или Физическое лицо», или «Строка или Число». Присвоить можно значение любого из разрешённых типов. Перед обработкой полезно узнать, что лежит внутри:

Если ТипЗнч(Объект.Получатель) = Тип("СправочникСсылка.Контрагенты") Тогда
    // логика для контрагента
КонецЕсли;

Если присвоить значение не того типа, платформа приведёт его к типу реквизита. Несовместимое значение превратится в пустое — без ошибки и без сообщения. Строка длиннее, чем задано в свойствах реквизита, обрежется. Привести значение явно можно так:

ОписаниеТипаСуммы = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2));
Сумма = ОписаниеТипаСуммы.ПривестиЗначение("1234.567"); // 1234.57

Пустое значение для очистки реквизита у каждого типа своё:

ТипПустое значение
Число0
Строка""
Дата'00010101' или Дата(1, 1, 1)
БулевоЛожь
СсылкаПустаяСсылка() соответствующего менеджера
Составной типНеопределено

Проверка значения и обработка ошибок при записи

Присвоить можно что угодно, но запись должна пройти проверки. Ошибки ловят тремя механизмами.

1. Проверка заполнения. Обработчик ОбработкаПроверкиЗаполнения в модуле объекта вызывается при интерактивной записи и при явном вызове ПроверитьЗаполнение():

Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
    Если СуммаДокумента < 0 Тогда
        Сообщение = Новый СообщениеПользователю;
        Сообщение.Текст = "Сумма документа не может быть отрицательной";
        Сообщение.Поле  = "СуммаДокумента";
        Сообщение.УстановитьДанные(ЭтотОбъект);
        Сообщение.Сообщить();
        Отказ = Истина;
    КонецЕсли;
КонецПроцедуры

При программной записи через Записать() эта проверка сама не запускается. Если она нужна, вызовите ДокОбъект.ПроверитьЗаполнение() перед записью и анализируйте результат.

2. Отказ в ПередЗаписью. Установка Отказ = Истина отменяет запись. Код, который вызывал Записать(), получит исключение.

3. Попытка — Исключение. Вокруг записи в общих модулях и обработках:

Попытка
    ДокОбъект.Заблокировать();
    ДокОбъект.Комментарий = Текст;
    ДокОбъект.Записать();
Исключение
    ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
    ЗаписьЖурналаРегистрации("Изменение реквизита", УровеньЖурналаРегистрации.Ошибка, , ДокОбъект.Ссылка, ТекстОшибки);
КонецПопытки;

Заблокировать() ставит объектную блокировку: если документ сейчас открыт и редактируется у другого пользователя, вы сразу получите исключение, а не перезапишете его правки.

Когда меняете несколько объектов, которые должны измениться вместе, оберните запись в транзакцию:

НачатьТранзакцию();
Попытка
    Объект1.Записать();
    Объект2.Записать();
    ЗафиксироватьТранзакцию();
Исключение
    ОтменитьТранзакцию();
    ВызватьИсключение;
КонецПопытки;
Диагностика: выберите симптом

Частые вопросы

Можно ли изменить реквизит без записи всего объекта?
Нет. Платформа пишет объект целиком: все реквизиты и табличные части. Изменить одно поле в таблице базы напрямую встроенный язык не позволяет.
Почему запросом нельзя присвоить значение реквизиту?
Язык запросов 1С только читает данные. Команд UPDATE и INSERT в нём нет. Запросом выбирают ссылки, а меняют уже через объекты.
Как присвоить значение реквизиту сразу у многих элементов без программирования?
В типовых конфигурациях на БСП есть обработка группового изменения реквизитов. Её ищут через «Все функции» или в разделе администрирования. Перед запуском сделайте резервную копию.
Чем `Константы.Имя.Установить()` отличается от менеджера значения?
Результат одинаковый. Менеджер значения позволяет сначала заполнить значение, а потом записать его с вызовом обработчиков записи константы.
Почему при записи документа значение реквизита перезаписывается другим?
Скорее всего, его заново рассчитывает обработчик ПередЗаписью или подписка на событие. Найдите код через глобальный поиск по имени реквизита в конфигураторе.