Как программно установить признак в документе при формировании другого документа в 1С 8.3?

Программист 1С v8.3 (Управляемые формы) Управленческий учет Торговля и дистрибуция
← На главную

В процессе разработки в среде 1С:Предприятие 8.3 на управляемых формах часто возникает задача: при выполнении определенного действия (например, нажатии кнопки) создать новый документ и одновременно «отметить» исходный документ, установив в нем соответствующий флаг или значение реквизита. Начинающие разработчики часто сталкиваются с ошибкой Поле объекта недоступно для записи. Разберем подробно, почему это происходит и как правильно реализовать эту задачу, соблюдая принципы клиент-серверного взаимодействия.

Анализ проблемы: почему код «не пашет»?

Рассмотрим типичную ситуацию. У нас есть форма списка документа Доставка. Мы хотим выделить несколько строк, нажать кнопку и получить два результата: сформированные документы РеализацияТоваровУслуг и установленную галочку ТоварРеализован в исходных документах Доставка.

Ошибка Поле объекта недоступно для записи (ТоварРеализован) возникает по двум основным причинам:

  1. Попытка изменения ссылки вместо объекта. В 1С ссылка (ДокументСсылка) — это лишь указатель на запись в базе данных. Она доступна «на чтение», но через нее нельзя менять данные. Чтобы изменить реквизит, нужно получить объект документа.
  2. Работа на клиенте. В управляемом приложении изменять данные в базе напрямую через ПолучитьОбъект() и метод Записать() можно только на сервере. Клиентская часть приложения отвечает за интерфейс, а серверная — за работу с данными.

Шаг 1. Подготовка обработчика на клиенте

Для начала проанализируем, как должна выглядеть процедура нажатия кнопки. На клиенте мы собираем информацию о том, какие строки выбрал пользователь, и передаем эти данные серверу. Рассмотрим пример кода для команды формы:


&НаКлиенте
Процедура СформироватьРеализации(Команда)
    // Получаем массив ссылок выделенных строк в списке
    МассивВыделенныхСтрок = Элементы.Список.ВыделенныеСтроки;
    
    Если МассивВыделенныхСтрок.Количество() = 0 Тогда
        ПоказатьПредупреждение(, "Выберите хотя бы один документ доставки!");
        Возврат;
    КонецЕсли;

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

Шаг 2. Реализация логики на сервере

Теперь перейдем к самой важной части — серверной функции. Проанализируем ситуацию: нам нужно не просто создать новый документ, но и обновить старый. Чтобы сделать это эффективно, мы будем использовать запрос для получения данных из исходных документов и цикл для их обработки.

В коде ниже мы объединим создание нового документа РеализацияТоваровУслуг и установку галочки в документе Доставка.


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

Разберем нюансы работы с объектами

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

Проанализируем важные моменты оптимизации:

Альтернативные подходы к решению

Рассмотрим ситуацию, когда логика усложняется. Если документов много, постоянная перезапись Доставки может нагружать систему. В таких случаях программисты 1С часто используют Регистры сведений. Вместо того чтобы добавлять реквизит-галочку в сам документ, создается регистр СтатусыДоставок, где в качестве измерения выступает ссылка на документ, а в качестве ресурса — статус «Реализован». Это позволяет обновлять статус, не перезаписывая тяжелый объект документа.

Также не забудьте про полезную литературу для закрепления материала. Как советовали на форуме, книга «Радченко М.Г. 1С:Предприятие 8.3. Практическое пособие разработчика» является библией для понимания клиент-серверного взаимодействия и работы с объектами базы данных. Разберите в ней главы, посвященные управляемым формам и программному созданию объектов.

Таким образом, мы выяснили, что для успешного решения задачи необходимо четко разделять интерфейсную логику (выбор строк в списке на клиенте) и бизнес-логику (манипуляция данными на сервере через объекты). Установка реквизита в исходном документе после создания зависимого документа — это стандартная процедура, требующая внимательного отношения к типам данных (ссылка vs объект) и обработке исключительных ситуаций.

← На главную