В разработке на платформе 1С:Предприятие 8.3 механизм подбора через "корзину" является одним из самых удобных способов заполнения табличных частей для пользователя. Однако при его реализации часто возникают вопросы: как не затереть уже добавленные строки, как вызвать дополнительное окно для ввода количества и как правильно работать с динамическими списками. В этой статье мы подробно разберем, как решить эти задачи на примере документа ДанныеДляРасчетаЗарплаты.
Рассмотрим типичную ситуацию: разработчик реализовал подбор, но при каждом новом открытии формы подбора и переносе данных в документ старые строки исчезают, заменяясь новыми. Это происходит из-за использования метода Загрузить(). Проанализируем, как правильно организовать перенос данных из временного хранилища.
Вместо полной замены содержимого табличной части, нам необходимо обходить полученную из хранилища таблицу в цикле и добавлять строки по одной. Рассмотрим код процедуры на сервере, которая обрабатывает результат выбора:
&НаСервере
Процедура ОбработатьПодборНаСервере(АдресВременногоХранилища)
// Получаем данные из корзины (таблицу значений)
Корзина = ПолучитьИзВременногоХранилища(АдресВременногоХранилища);
Для каждого Стр Из Корзина Цикл
// Поиск существующей строки, если нужно объединить объемы
Отбор = Новый Структура("ВидРабот", Стр.ВидРабот);
НайденныеСтроки = Объект.ВыполненныеРаботы.НайтиСтроки(Отбор);
Если НайденныеСтроки.Количество() > 0 Тогда
// Если такая работа уже есть, просто суммируем объем
НайденнаяСтрока = НайденныеСтроки[0];
НайденнаяСтрока.ОбъемВыполненныхРабот = НайденнаяСтрока.ОбъемВыполненныхРабот + Стр.ОбъемВыполненныхРабот;
Иначе
// Если работы нет, добавляем новую строку
НовСтр = Объект.ВыполненныеРаботы.Добавить();
ЗаполнитьЗначенияСвойств(НовСтр, Стр);
// Устанавливаем значения по умолчанию для новых строк
НовСтр.КоэффициентИсполнения = 1;
НовСтр.ПроцентИсполнения = 100;
// Вызываем типовые механизмы заполнения, если они предусмотрены в конфигурации
ЗаполнитьСтрокуВыполненныхРабот(НовСтр, Истина, Ложь);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Использование метода НайтиСтроки() позволяет нам избежать дублирования позиций. Если бизнес-логика предполагает, что одна и та же работа может встречаться в документе несколько раз разными строками, то условие поиска можно опустить и всегда использовать Добавить().
Зачастую просто выбрать элемент из списка недостаточно — пользователю нужно сразу указать объем работ или процент выполнения. Для этого логично использовать вспомогательную форму ввода. Разберем по шагам, как это реализовать через ОписаниеОповещения.
Во-первых, в форме подбора при выборе элемента из списка мы должны не сразу добавлять его в корзину, а открывать форму ввода:
&НаКлиенте
Процедура СписокВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
// Подготавливаем параметры для передачи в форму ввода
ДополнительныеПараметры = Новый Структура;
// Важно: если список построен по регистру, ВыбраннаяСтрока может быть КлючомЗаписи.
// В таком случае получаем саму ссылку через ТекущиеДанные.
Если ТипЗнч(ВыбраннаяСтрока) <> Тип("СправочникСсылка.ВидыРаботСотрудников") Тогда
ВидРаботСсылка = Элементы.СписокВидовРабот.ТекущиеДанные.ВидРабот;
Иначе
ВидРаботСсылка = ВыбраннаяСтрока;
КонецЕсли;
ДополнительныеПараметры.Вставить("ВидРабот", ВидРаботСсылка);
// Настраиваем оповещение, которое сработает после закрытия формы ввода
ОписаниеОповещения = Новый ОписаниеОповещения("ДобавитьВКорзинуПослеВыбораКоличества", ЭтотОбъект, ДополнительныеПараметры);
// Открываем вспомогательную форму
ОткрытьФорму("Документ.ДанныеДляРасчетаЗарплаты.Форма.ФормаКолДетали", , ЭтаФорма, , , , ОписаниеОповещения, РежимОткрытияОкнаФормы.БлокироватьОкноВладельца);
КонецПроцедуры
Во-вторых, в самой вспомогательной форме (например, ФормаКолДетали) при нажатии кнопки "ОК" мы собираем данные в структуру и закрываем форму, передавая результат обратно:
&НаКлиенте
Процедура ОК(Команда)
// Проверка заполнения обязательных полей
Если ОбъемВыполненныхРабот = 0 Тогда
Сообщить("Не заполнено количество!");
Возврат;
КонецЕсли;
РезультатВыбора = Новый Структура;
РезультатВыбора.Вставить("ОбъемВыполненныхРабот", ОбъемВыполненныхРабот);
РезультатВыбора.Вставить("НомерДетали", НомерДетали);
РезультатВыбора.Вставить("КоэффициентИсполнения", КоэффициентИсполнения);
РезультатВыбора.Вставить("ПроцентИсполнения", ПроцентИсполнения);
// Закрываем форму и передаем структуру в процедуру оповещения
Закрыть(РезультатВыбора);
КонецПроцедуры
В-третьих, реализуем процедуру обратного вызова в основной форме подбора, которая добавит данные в корзину:
&НаКлиенте
Процедура ДобавитьВКорзинуПослеВыбораКоличества(Результат, ДополнительныеПараметры) Экспорт
Если Результат = Неопределено Тогда
Возврат; // Пользователь закрыл форму без нажатия ОК
КонецЕсли;
// Добавляем строку в таблицу "Корзина" на форме подбора
НоваяСтрока = Корзина.Добавить();
// Заполняем ссылку на вид работ из параметров, переданных ранее
ЗаполнитьЗначенияСвойств(НоваяСтрока, ДополнительныеПараметры);
// Заполняем введенные пользователем цифры
ЗаполнитьЗначенияСвойств(НоваяСтрока, Результат);
КонецПроцедуры
Проанализируем ситуацию, когда ДинамическийСписок в форме подбора основан не на справочнике, а на произвольном запросе (например, к регистру сведений с расценками). В этом случае параметр ВыбраннаяСтрока в событии Выбор будет содержать РегистрСведенийКлючЗаписи, а не ссылку на объект.
Для корректного получения ссылки на справочник ВидыРаботСотрудников следует обращаться к свойству ТекущиеДанные элемента формы Таблица. Это гарантирует, что вы получите значения всех колонок, присутствующих в строке запроса, включая скрытые.
Важный совет: При переносе данных из корзины в документ всегда используйте Временное хранилище. Это позволяет передавать большие объемы данных между формами без лишней нагрузки на клиент-серверный канал связи, передавая только строковый адрес (УИД) данных в памяти сервера.
Таким образом, мы построили надежную цепочку подбора:
КлючЗаписи).Объект документа с проверкой на дубли и дозаполнением реквизитов.Этот подход делает интерфейс профессиональным и исключает случайную потерю данных при работе пользователя.