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