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

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

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

Анализируем причину проблемы: Объект vs ДанныеФормы

Рассмотрим типичную ситуацию, описанную в теме. Разработчик пытается вызвать Объект.Записать() или ЭтаФорма.Записать() внутри клиентской процедуры, но данные в базе не обновляются или метод вовсе недоступен. Выясним причину такого поведения. В управляемом приложении переменная Объект, доступная в модуле формы, не является самим документом. Это специальный тип данных — ДанныеФормыСтруктура.

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

Правильный алгоритм записи и закрытия из формы

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


&НаКлиенте
Процедура МояКомандаРаспределитьИЗакрыть(Команда)

    // 1. Изменяем данные в табличной части (на клиенте или сервере)
    // Допустим, мы вызываем серверную процедуру для расчетов
    РаспределитьТоварыНаСервере();
    
    // 2. Подготавливаем параметры записи
    // Здесь можно указать режим записи: Запись, Проведение или ОтменаПроведения
    ПараметрыЗаписи = Новый Структура;
    ПараметрыЗаписи.Вставить("РежимЗаписи", РежимЗаписиДокумента.Запись);
    
    // 3. Вызываем метод записи ФОРМЫ. 
    // Именно метод Записать() формы инициирует передачу данных на сервер
    Если Записать(ПараметрыЗаписи) Тогда
        // 4. Если запись прошла успешно, закрываем форму
        Закрыть();
    КонецЕсли;

КонецПроцедуры

В этом примере мы используем метод Записать() самой формы. Обратите внимание: мы не пишем Объект.Записать(). Если метод возвращает Истина, это означает, что все проверки (включая ПередЗаписью на сервере) пройдены успешно и данные зафиксированы в базе. Только после этого можно безопасно вызывать Закрыть().

Разберем нюансы работы с табличными частями

Часто возникает вопрос: где лучше менять табличную часть — на клиенте или на сервере? Посмотрим на ситуацию глубже. Если алгоритм изменения строк сложный (требуются запросы к остаткам, обращение к другим справочникам), то однозначно следует использовать серверный контекст.

Рассмотрим пример серверной процедуры, которая меняет данные:


&НаСервере
Процедура РаспределитьТоварыНаСервере()
    // Работаем напрямую с реквизитом формы "Объект"
    // Платформа сама синхронизирует изменения с экранными данными
    Для Каждого СтрокаТовара Из Объект.Товары Цикл
        // Логика пересчета
        СтрокаТовара.Количество = СтрокаТовара.Количество * 1.1; // Условно
    КонецЦикла;
    
    // Важно: форма должна узнать, что данные изменились
    Модифицированность = Истина;
КонецПроцедуры

Если же вы решите записывать объект напрямую на сервере через ДокументОбъект.Записать(), минуя методы формы, вы столкнетесь с проблемой блокировок или ошибкой «Данные были изменены или удалены другим пользователем». Это происходит потому, что версия данных в памяти формы перестает соответствовать версии в базе данных. Поэтому всегда инициируйте запись через форму, если вы находитесь в её контексте.

Типичная ошибка: путаница с ЭтотОбъект

Проанализируем еще один момент из обсуждения. Автор темы упоминал, что в отладчике он видит изменения в ЭтотОбъект.Товары, но не видит их в ссылке. В управляемых формах ЭтотОбъект внутри модуля формы ссылается на саму Форму, а не на документ. Если на форме создан реквизит с именем «Товары», который не связан с данными основного объекта (документа), то любые изменения в нем не попадут в документ при сохранении.

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

Дополнительные параметры метода Записать()

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

Использование флага Модифицированность = Истина; также является хорошим тоном. Это заставляет платформу считать, что форма изменена, и активирует стандартные механизмы проверки при закрытии, если вдруг программная запись по какой-то причине не была вызвана.

Подведем итог: для реализации цепочки «изменить — записать — закрыть» мы должны изменить данные в Объект.ТабличнаяЧасть, вызвать метод Записать() самой управляемой формы и, при успешном результате, вызвать Закрыть(). Это обеспечит целостность данных и отсутствие конфликтов блокировок в многопользовательской среде.

← На главную