Как исправить ошибку «Поле не доступно для записи» при программном изменении документа в 1С?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

В процессе разработки на платформе «1С:Предприятие 8» программисты часто сталкиваются с ситуацией, когда при попытке изменить реквизит документа система выдает ошибку «Поле не доступно для записи». Это классическая проблема, связанная с непониманием объектной техники платформы. В данной статье мы подробно разберем, почему возникает эта ошибка, как правильно переходить от ссылки к объекту и какие дополнительные нюансы записи и проведения документов следует учитывать.

Разберем причину: Ссылка против Объекта

Проанализируем исходный код, который вызвал затруднения. Основная ошибка заключается в использовании переменной Док, полученной через метод Выбрать(). В 1С метод Выбрать() возвращает выборку ссылок (ДокументСсылка). Давайте выясним, в чем принципиальная разница между ссылкой и объектом:

Таким образом, когда мы пишем Док.Комментарий = НомерВ, где Док является ссылкой, система блокирует это действие, так как ссылка не обладает правами на изменение данных.

Шаг 1: Правильное получение объекта для записи

Чтобы внести изменения в документ, нам необходимо на основе имеющейся ссылки получить полноценный объект. Рассмотрим, как должен выглядеть исправленный фрагмент кода:


Пока Док.Следующий() Цикл 
    Если Док.Проведен = Ложь Тогда
        // Получаем объект из ссылки
        ДокОбъект = Док.ПолучитьОбъект();
        
        // Теперь мы работаем с ДокОбъект, поле Комментарий доступно
        ДокОбъект.Комментарий = НомерВ;
        
        // Сообщаем номер для визуального контроля
        Сообщить("Обработка документа: " + ДокОбъект.Номер);
        
        // Записываем изменения в базу данных
        ДокОбъект.Записать();
    КонецЕсли;
    
    // Сохраняем номер текущего документа для следующей итерации
    НомерВ = Док.Номер;
КонецЦикла;

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

Шаг 2: Исправление метода проведения (переход с 7.7 на 8.х)

В тексте обсуждения было замечено, что автор пытался вызвать метод Док.Провести(). Это типичная ошибка разработчиков, которые ранее работали с версией 1С:Предприятие 7.7. В современной платформе 8.х отдельного метода Провести() у объекта документа не существует.

Проанализируем, как правильно выполнять проведение. Для этого используется метод Записать(), в который передается специальный параметр — РежимЗаписиДокумента. Рассмотрим пример:


// Просто запись без изменения статуса проведения
ДокОбъект.Записать(РежимЗаписиДокумента.Запись);

// Запись с выполнением проведения (движения по регистрам)
ДокОбъект.Записать(РежимЗаписиДокумента.Проведение);

// Отмена проведения
ДокОбъект.Записать(РежимЗаписиДокумента.ОтменаПроведения);

Если ваша задача — просто изменить комментарий, не пересчитывая движения документа по счетам или регистрам накопления, используйте РежимЗаписиДокумента.Запись. Это сэкономит ресурсы сервера и ускорит выполнение кода.

Оптимизация: Почему запрос лучше, чем Выборка?

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

  1. Скорость: Запрос позволяет отобрать только нужные документы (например, только непроведенные) прямо на стороне СУБД. В случае с Выбрать() система сначала получает все документы, а потом вы фильтруете их через Если Док.Проведен = Ложь, что крайне неэффективно при больших объемах данных.
  2. Экономия памяти: Запрос может извлекать только те поля, которые вам нужны (например, только Ссылка), а не весь документ целиком.

Посмотрим на пример того, как можно переписать этот алгоритм оптимально:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   Товар.Ссылка КАК Ссылка,
    |   Товар.Номер КАК Номер
    |ИЗ
    |   Документ.Товар КАК Товар
    |ГДЕ
    |   Товар.Дата МЕЖДУ &Нач И &Кон
    |   И Товар.Проведен = ЛОЖЬ";

Запрос.УстановитьПараметр("Нач", Объект.Нач);
Запрос.УстановитьПараметр("Кон", Объект.Кон);

РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

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

Архитектурные советы и транзакции

Проанализируем еще один важный момент, затронутый в обсуждении: выполнение записи в процедуре печати. В системе 1С существует разделение ответственности (Separation of Concerns). Процедуры печати должны только формировать печатную форму, не изменяя данные в базе.

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

Если вам все же необходимо массово изменить документы, рекомендуем придерживаться следующих правил:

Подводя итог, можно сказать, что решение проблемы «Поле не доступно для записи» кроется в четком разграничении ссылочных и объектных типов данных. Понимая эти основы и следуя стандартам разработки 1С, вы сможете писать надежный и эффективный код.

← На главную