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