Как программно реализовать групповое изменение реквизита в выбранных документах 1С?

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия
← На главную

В процессе работы с типовыми конфигурациями, такими как 1С:Бухгалтерия 3.0, бухгалтеры часто сталкиваются с необходимостью быстро проставить специфические идентификаторы или номера в пачку документов. Стандартная обработка «Групповое изменение реквизитов» мощная, но иногда избыточная для одной конкретной задачи. Разберем, как реализовать удобный механизм изменения реквизита непосредственно из формы списка документов.

Основа решения: работа с выделенными строками

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

Когда пользователь выделяет строки, свойство Элементы.Список.ВыделенныеСтроки возвращает массив идентификаторов этих строк (ссылок на объекты). Наша задача — передать этот массив на сервер и обработать каждый документ в цикле.

Шаг 1. Создание команды и клиентской процедуры

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

Пример кода на клиенте:


&НаКлиенте
Процедура ДобавитьНомер(Команда)
    
    // Получаем массив выделенных строк
    ВыбранныеДокументы = Элементы.Список.ВыделенныеСтроки;
    
    Если ВыбранныеДокументы.Количество() = 0 Тогда
        ПоказатьПредупреждение(, "Не выбрано ни одного документа!");
        Возврат;
    КонецЕсли;
    
    // Запрашиваем номер у пользователя
    ОписаниеОповещения = Новый ОписаниеОповещения("ПослеВводаНомера", ЭтотОбъект, ВыбранныеДокументы);
    ПоказатьВводЗначения(ОписаниеОповещения, 0, "Введите номер для простановки в документы", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(4)));
    
КонецПроцедуры

&НаКлиенте
Процедура ПослеВводаНомера(Значение, ДополнительныеПараметры) Экспорт
    
    Если Значение = Неопределено Тогда
        Возврат; // Пользователь нажал Отмена
    КонецЕсли;
    
    ВыбранныеДокументы = ДополнительныеПараметры;
    
    // Добавляем запрос подтверждения для защиты от случайных нажатий
    ТекстВопроса = СтрШаблон("Будет изменен номер в %1 документах. Продолжить?", ВыбранныеДокументы.Количество());
    ОписаниеОповещения = Новый ОписаниеОповещения("ВыполнитьИзменениеПослеПодтверждения", ЭтотОбъект, Новый Структура("Документы, Номер", ВыбранныеДокументы, Значение));
    ПоказатьВопрос(ОписаниеОповещения, ТекстВопроса, РежимДиалогаВопрос.ДаНет);
    
КонецПроцедуры

Шаг 2. Серверная обработка документов

Теперь выясним, как правильно записать данные на сервере. Важно помнить, что работа с объектами базы данных (ПолучитьОбъект) возможна только в серверном контексте. Рассмотрим процедуру, которая обходит массив ссылок и меняет реквизит.


&НаКлиенте
Процедура ВыполнитьИзменениеПослеПодтверждения(Результат, Параметры) Экспорт
    
    Если Результат <> КодВозвратаДиалога.Да Тогда
        Возврат;
    КонецЕсли;
    
    // Вызываем серверный метод
    РезультатОбработки = ИзменитьРеквизитНаСервере(Параметры.Документы, Параметры.Номер);
    
    // Обновляем список, чтобы увидеть изменения
    Элементы.Список.Обновить();
    
    // Оповещаем пользователя об успехе
    ТекстОповещения = СтрШаблон("Обработано документов: %1 из %2", РезультатОбработки.Успешно, Параметры.Документы.Количество());
    ПоказатьОповещениеПользователя("Групповое изменение", , ТекстОповещения);
    
КонецПроцедуры

&НаСервереБезКонтекста
Функция ИзменитьРеквизитНаСервере(МассивСсылок, НовыйНомер)
    
    Статистика = Новый Структура("Успешно, Ошибок", 0, 0);
    
    Для Каждого Ссылка Из МассивСсылок Цикл
        Попытка
            Объект = Ссылка.ПолучитьОбъект();
            
            // Предположим, наш реквизит называется "ЛичныйНомерБухгалтера"
            Объект.ЛичныйНомерБухгалтера = НовыйНомер;
            
            // Используем режим записи "Запись", чтобы не инициировать перепроведение,
            // если документ уже проведен.
            Объект.Записать(РежимЗаписиДокумента.Запись);
            
            Статистика.Успешно = Статистика.Успешно + 1;
        Исключение
            // Логируем ошибку, если документ заблокирован или нет прав
            ЗаписьЖурналаРегистрации("ГрупповоеИзменение", УровеньЖурналаРегистрации.Ошибка, , , КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
            Статистика.Ошибок = Статистика.Ошибок + 1;
        КонецПопытки;
    КонецЦикла;
    
    Возврат Статистика;
    
КонецФункции

Важные технические нюансы и "лучшие практики"

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

  1. Обработка проведенных документов и периодов. Если документ находится в закрытом периоде, метод Объект.Записать() вызовет ошибку. Если реквизит носит чисто справочный характер и не влияет на проводки, программисты иногда используют Объект.ОбменДанными.Загрузка = Истина, чтобы обойти проверки. Однако это опасный метод, его стоит использовать только в крайнем случае.
  2. Транзакции и блокировки. При записи объекта в цикле, один из документов может быть открыт другим пользователем. В коде выше мы использовали блок Попытка...Исключение. Это позволяет алгоритму не "падать" целиком, если один документ из ста заблокирован.
  3. Использование БСП. В 1С:Бухгалтерия 3.0 встроена Библиотека стандартных подсистем (БСП). Вместо написания своего велосипеда, можно использовать общий модуль ОбщегоНазначения.ЗаписатьОбъект или механизмы фонового выполнения задач, если документов тысячи.
  4. Обновление интерфейса. После серверного вызова обязательно вызывайте Элементы.Список.Обновить() на клиенте, иначе бухгалтер не увидит изменения сразу и может нажать кнопку повторно.

Альтернативный вариант: Внешняя обработка заполнения

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

Подведем итог: для реализации задачи достаточно использовать связку Элементы.Список.ВыделенныеСтроки на клиенте и цикл с ПолучитьОбъект() на сервере. Не забывайте добавлять подтверждение действия пользователем (метод ПоказатьВопрос) и обрабатывать ошибки блокировок данных.

← На главную