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