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