В процессе работы с типовыми конфигурациями, такими как 1С:Бухгалтерия 3.0, бухгалтеры часто сталкиваются с необходимостью быстро проставить специфические идентификаторы или номера в пачку документов. Стандартная обработка «Групповое изменение реквизитов» мощная, но иногда избыточная для одной конкретной задачи. Разберем, как реализовать удобный механизм изменения реквизита непосредственно из формы списка документов.
Для реализации задачи нам необходимо получить список ссылок на документы, которые пользователь выделил мышкой в списке. В управляемых формах 1С за это отвечает свойство элемента формы Список (или другого имени динамического списка) — ВыделенныеСтроки. Рассмотрим подробнее, как это работает.
Когда пользователь выделяет строки, свойство Элементы.Список.ВыделенныеСтроки возвращает массив идентификаторов этих строк (ссылок на объекты). Наша задача — передать этот массив на сервер и обработать каждый документ в цикле.
Проанализируем ситуацию: нам нужно сначала спросить у пользователя номер, а затем выполнить действие. Вместо создания отдельной формы для ввода одного числа, лучше использовать стандартный метод платформы ПоказатьВводЗначения. Это сделает интерфейс более легким.
Пример кода на клиенте:
&НаКлиенте
Процедура ДобавитьНомер(Команда)
// Получаем массив выделенных строк
ВыбранныеДокументы = Элементы.Список.ВыделенныеСтроки;
Если ВыбранныеДокументы.Количество() = 0 Тогда
ПоказатьПредупреждение(, "Не выбрано ни одного документа!");
Возврат;
КонецЕсли;
// Запрашиваем номер у пользователя
ОписаниеОповещения = Новый ОписаниеОповещения("ПослеВводаНомера", ЭтотОбъект, ВыбранныеДокументы);
ПоказатьВводЗначения(ОписаниеОповещения, 0, "Введите номер для простановки в документы", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(4)));
КонецПроцедуры
&НаКлиенте
Процедура ПослеВводаНомера(Значение, ДополнительныеПараметры) Экспорт
Если Значение = Неопределено Тогда
Возврат; // Пользователь нажал Отмена
КонецЕсли;
ВыбранныеДокументы = ДополнительныеПараметры;
// Добавляем запрос подтверждения для защиты от случайных нажатий
ТекстВопроса = СтрШаблон("Будет изменен номер в %1 документах. Продолжить?", ВыбранныеДокументы.Количество());
ОписаниеОповещения = Новый ОписаниеОповещения("ВыполнитьИзменениеПослеПодтверждения", ЭтотОбъект, Новый Структура("Документы, Номер", ВыбранныеДокументы, Значение));
ПоказатьВопрос(ОписаниеОповещения, ТекстВопроса, РежимДиалогаВопрос.ДаНет);
КонецПроцедуры
Теперь выясним, как правильно записать данные на сервере. Важно помнить, что работа с объектами базы данных (ПолучитьОбъект) возможна только в серверном контексте. Рассмотрим процедуру, которая обходит массив ссылок и меняет реквизит.
&НаКлиенте
Процедура ВыполнитьИзменениеПослеПодтверждения(Результат, Параметры) Экспорт
Если Результат <> КодВозвратаДиалога.Да Тогда
Возврат;
КонецЕсли;
// Вызываем серверный метод
РезультатОбработки = ИзменитьРеквизитНаСервере(Параметры.Документы, Параметры.Номер);
// Обновляем список, чтобы увидеть изменения
Элементы.Список.Обновить();
// Оповещаем пользователя об успехе
ТекстОповещения = СтрШаблон("Обработано документов: %1 из %2", РезультатОбработки.Успешно, Параметры.Документы.Количество());
ПоказатьОповещениеПользователя("Групповое изменение", , ТекстОповещения);
КонецПроцедуры
&НаСервереБезКонтекста
Функция ИзменитьРеквизитНаСервере(МассивСсылок, НовыйНомер)
Статистика = Новый Структура("Успешно, Ошибок", 0, 0);
Для Каждого Ссылка Из МассивСсылок Цикл
Попытка
Объект = Ссылка.ПолучитьОбъект();
// Предположим, наш реквизит называется "ЛичныйНомерБухгалтера"
Объект.ЛичныйНомерБухгалтера = НовыйНомер;
// Используем режим записи "Запись", чтобы не инициировать перепроведение,
// если документ уже проведен.
Объект.Записать(РежимЗаписиДокумента.Запись);
Статистика.Успешно = Статистика.Успешно + 1;
Исключение
// Логируем ошибку, если документ заблокирован или нет прав
ЗаписьЖурналаРегистрации("ГрупповоеИзменение", УровеньЖурналаРегистрации.Ошибка, , , КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
Статистика.Ошибок = Статистика.Ошибок + 1;
КонецПопытки;
КонецЦикла;
Возврат Статистика;
КонецФункции
Проанализируем ситуацию глубже. Простого цикла иногда недостаточно, если база данных большая, а документов много. Рассмотрим дополнительные аспекты:
Объект.Записать() вызовет ошибку. Если реквизит носит чисто справочный характер и не влияет на проводки, программисты иногда используют Объект.ОбменДанными.Загрузка = Истина, чтобы обойти проверки. Однако это опасный метод, его стоит использовать только в крайнем случае.Попытка...Исключение. Это позволяет алгоритму не "падать" целиком, если один документ из ста заблокирован.ОбщегоНазначения.ЗаписатьОбъект или механизмы фонового выполнения задач, если документов тысячи.Элементы.Список.Обновить() на клиенте, иначе бухгалтер не увидит изменения сразу и может нажать кнопку повторно.Рассмотрим совет из обсуждения: использование внешней обработки. Если вы не хотите снимать конфигурацию с поддержки или менять типовую форму списка, создайте внешнюю обработку с видом "Заполнение объекта". БСП позволяет подключать такие обработки к спискам документов. В этом случае в меню "Изменить выделенные" (или в подменю "Заполнение") появится ваша команда, и платформа сама передаст в обработку массив ссылок через параметр ОбъектыНазначения.
Подведем итог: для реализации задачи достаточно использовать связку Элементы.Список.ВыделенныеСтроки на клиенте и цикл с ПолучитьОбъект() на сервере. Не забывайте добавлять подтверждение действия пользователем (метод ПоказатьВопрос) и обрабатывать ошибки блокировок данных.