Программная работа с документами — это одна из самых частых задач разработчика 1С. Однако начинающие специалисты часто сталкиваются с ситуацией, когда код вроде бы написан верно, ошибок система не выдает, но данные в базе данных не обновляются. Рассмотрим на конкретном примере, почему это происходит и как правильно реализовать алгоритм изменения существующего документа.
Проанализируем ситуацию, описанную в теме. Разработчик пытается найти документ «Перемещение товаров» по номеру и дате, изменить его комментарий и сохранить изменения. Посмотрим на фрагмент кода, который не работает:
КорДок = Документы.ПеремещениеТоваров.НайтиПоНомеру(Результат.Номер, Результат.Дата);
КорДок.ПолучитьОбъект();
Комментарий = КорДок.Комментарий;
Комментарий = "Авто серии";
// Запись не происходит или не сохраняет данные
Выясним причину неудачи. В 1С существует четкое разделение на Ссылку (ДокументСсылка) и Объект (ДокументОбъект). Ссылка — это всего лишь «указатель» на запись в базе данных, она неизменяема. Для редактирования данных необходимо получить Объект в оперативную память.
Ошибка в приведенном коде заключается в том, что метод ПолучитьОбъект() вызывается «в пустоту». Он создает в памяти копию данных документа, но эта копия нигде не сохраняется, так как не присвоена переменной. Кроме того, попытка изменить переменную Комментарий никак не влияет на сам документ — это просто изменение локальной строковой переменной.
Разберем по шагам, как должен выглядеть корректный код для решения этой задачи. Нам необходимо получить ссылку, преобразовать ее в объект, изменить реквизит именно у объекта и вызвать метод Записать().
// Шаг 1. Находим ссылку на документ
КорДокСсылка = Документы.ПеремещениеТоваров.НайтиПоНомеру(Результат.Номер, Результат.Дата);
// Проверяем, найден ли документ, прежде чем работать с ним
Если Не КорДокСсылка.Пустая() Тогда
// Шаг 2. Получаем объект из ссылки и присваиваем его переменной
КорДокОбъект = КорДокСсылка.ПолучитьОбъект();
// Шаг 3. Изменяем реквизит ОБЪЕКТА, а не локальную переменную
КорДокОбъект.Комментарий = "Авто серии";
// Шаг 4. Записываем изменения в базу данных
КорДокОбъект.Записать();
КонецЕсли;
В этом примере КорДокОбъект является экземпляром типа ДокументОбъект.ПеремещениеТоваров. Только у этого типа данных доступен метод Записать(), который переносит изменения из оперативной памяти обратно в таблицу базы данных.
Рассмотрим подробнее метод НайтиПоНомеру. В конфигурациях вроде УПП или ERP для документов часто настроена периодичность нумерации (например, в пределах года). Если мы ищем документ только по номеру, не указывая дату, система может вернуть пустую ссылку или документ из другого года, если номера совпадают.
Всегда рекомендуется передавать второй параметр — дату. Это позволяет платформе ограничить период поиска нужным интервалом. Также хорошей практикой является проверка на Пустая(), чтобы избежать ошибок при попытке получить объект от несуществующего документа.
Метод Записать() может принимать параметры, определяющие поведение системы. Проанализируем основные режимы записи, которые могут понадобиться в работе:
Пример записи с проведением:
КорДокОбъект.Записать(РежимЗаписиДокумента.Проведение);
В сложных конфигурациях (УПП, КА, ERP) в модулях документов прописано огромное количество проверок: контроль остатков, заполнение аналитики, проверка прав. Если ваша задача — массово обновить только комментарии, выполнение всех этих проверок сильно замедлит процесс и может вызвать ошибки блокировок.
Посмотрим, как можно ускорить процесс с помощью свойства ОбменДанными.Загрузка. Установка этого флага в значение Истина сообщает системе, что запись производится программно (например, при обмене или групповой обработке), и большинство стандартных проверок в процедурах ПередЗаписью и ПриЗаписи будут пропущены.
КорДокОбъект = КорДокСсылка.ПолучитьОбъект();
КорДокОбъект.ОбменДанными.Загрузка = Истина;
КорДокОбъект.Комментарий = "Обновлено автоматически";
КорДокОбъект.Записать();
Важно: используйте этот режим осторожно. Если вы программно меняете суммы или количество, пропуск проверок может привести к нарушению логической целостности данных в системе.
Проанализируем ситуацию, когда документ заблокирован другим пользователем или база данных вернула ошибку при записи. Чтобы ваша обработка не прервалась аварийно, обязательно используйте конструкцию Попытка ... Исключение.
Попытка
КорДокОбъект.Записать();
Исключение
ТекстОшибки = ОписаниеОшибки();
Сообщить("Не удалось записать документ " + КорДокСсылка + ". Причина: " + ТекстОшибки);
// Здесь можно записать ошибку в лог или журнал регистрации
КонецПопытки;
Такой подход гарантирует, что даже если один документ из тысячи не удастся записать, программа продолжит обработку остальных данных.
Иногда требуется, чтобы логика в модуле документа знала, что запись инициирована вашим скриптом. Для этого удобно использовать ДополнительныеСвойства. Это структура, которая «живет» внутри объекта во время сеанса записи и доступна во всех обработчиках модуля.
КорДокОбъект.ДополнительныеСвойства.Вставить("ПересчетНеТребуется", Истина);
КорДокОбъект.Записать();
Внутри модуля документа (например, в ПередЗаписью) вы сможете проверить это свойство и решить, нужно ли выполнять тяжелые вычисления или нет.
Подведем итог: для успешной программной записи документа всегда работайте с Объектом, полученным из ссылки, не забывайте проверять результат поиска на валидность и используйте обработку исключений для повышения надежности вашего кода.