Как при проведении документа добавить данные в табличную часть справочника?

Программист 1С v8.3 (Управляемые формы) Управленческий учет Торговля и дистрибуция
← На главную

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

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

Решение 1: Прямое изменение объекта справочника

Этот способ заключается в том, чтобы в момент проведения документа получить программный доступ к объекту нужного клиента и добавить в его табличную часть новые строки.

Основная логика и частые ошибки

Главная ошибка, которую часто допускают новички, — это попытка создать нового клиента вместо изменения существующего. Код вроде СпрКлиенты = Справочники.Клиенты.СоздатьЭлемент() всегда будет создавать пустой элемент справочника, а не работать с тем, который выбран в документе.

Правильный алгоритм действий таков:

  1. Весь код должен находиться в модуле объекта документа "Реализация товара" (или аналогичного), внутри процедуры ОбработкаПроведения(). Это гарантирует, что изменения будут внесены только после успешного проведения документа.
  2. В документе уже есть реквизит, который хранит ссылку на клиента (например, реквизит шапки `Клиент`).
  3. Чтобы изменить данные этого клиента, нам нужно из его ссылки получить полноценный объект. Для этого используется метод ПолучитьОбъект().
  4. Получив объект, мы можем обращаться к его табличным частям и добавлять новые строки методом Добавить().
  5. После внесения всех изменений объект клиента необходимо сохранить в базе данных с помощью метода Записать().

Пример кода

Посмотрим на пример реализации. Предположим, в документе "РеализацияТовара" есть реквизит шапки Клиент (тип `СправочникСсылка.Клиенты`) и табличная часть Товары с колонкой Номенклатура. В справочнике "Клиенты" есть табличная часть Автомобили с колонкой НаименованиеАвто.


// Код размещается в модуле объекта документа "РеализацияТовара"
// в процедуре ОбработкаПроведения()

// Получаем ссылку на клиента из реквизита документа
СсылкаНаКлиента = ЭтотОбъект.Клиент;

// Обязательно проверяем, что клиент в документе указан
Если НЕ СсылкаНаКлиента.Пустая() Тогда

    // Получаем ОБЪЕКТ справочника для его последующего изменения
    КлиентОбъект = СсылкаНаКлиента.ПолучитьОбъект();

    // Перебираем все строки из табличной части "Товары" нашего документа
    Для Каждого ТекСтрокаТовары Из ЭтотОбъект.Товары Цикл

        // Добавляем новую пустую строку в табличную часть "Автомобили" у клиента
        НоваяСтрокаАвто = КлиентОбъект.Автомобили.Добавить();

        // Заполняем реквизиты новой строки данными из документа
        НоваяСтрокаАвто.НаименованиеАвто = ТекСтрокаТовары.Номенклатура;
        // Можно добавить и другие данные, например, договор или дату покупки
        // НоваяСтрокаАвто.Договор = ЭтотОбъект.ДоговорКонтрагента;
        // НоваяСтрокаАвто.ДатаПокупки = ЭтотОбъект.Дата;

    КонецЦикла;

    // После добавления всех строк записываем измененный объект клиента в базу данных.
    // Важно делать это один раз после цикла, а не внутри него.
    КлиентОбъект.Записать();

КонецЕсли;

Недостатки прямого подхода

Несмотря на то, что этот метод работает, он считается неоптимальным и несет в себе риски:

Решение 2: Использование регистра сведений (Рекомендуемый подход)

Это более правильный и масштабируемый метод, который соответствует лучшим практикам разработки на платформе 1С. Суть в том, чтобы не хранить историю продаж внутри справочника, а вынести ее в отдельный объект — регистр сведений. Карточка клиента при этом не хранит данные, а лишь динамически их отображает из этого регистра.

Разберем реализацию по шагам.

Шаг 1. Создание регистра сведений

В конфигураторе создадим новый объект — Регистр сведений. Назовем его, например, "ПриобретенныеАвтомобили".

  1. На вкладке "Основные" установим Режим записи: Подчинение регистратору. Это ключевая настройка, которая свяжет записи регистра с документами и обеспечит автоматическое удаление записей при отмене проведения.
  2. На вкладке "Данные" определим структуру регистра:
    • Измерения (то, что описывает уникальность записи):
      • Клиент (тип: СправочникСсылка.Клиенты)
      • Автомобиль (тип: СправочникСсылка.Номенклатура)
    • Ресурсы (дополнительные данные, связанные с измерениями):
      • Договор (тип: СправочникСсылка.ДоговорыКонтрагентов)
      • Сумма (тип: Число)
  3. На вкладке "Регистраторы" поставим галочку напротив нашего документа "РеализацияТовара".

Важно: в сам справочник "Клиенты" мы не добавляем табличную часть "Автомобили". Он остается "чистым".

Шаг 2. Запись данных в регистр при проведении документа

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


// Код размещается в модуле объекта документа "РеализацияТовара"
// в процедуре ОбработкаПроведения()

// Устанавливаем флаг, что этот документ будет записывать движения в наш регистр
Движения.ПриобретенныеАвтомобили.Записывать = Истина;

// Перебираем строки табличной части "Товары"
Для Каждого ТекСтрокаТовары Из ЭтотОбъект.Товары Цикл

    // Создаем новое движение (запись) в регистре
    Движение = Движения.ПриобретенныеАвтомобили.Добавить();

    // Заполняем измерения
    Движение.Период = Дата; // Период записи
    Движение.Клиент = ЭтотОбъект.Клиент;
    Движение.Автомобиль = ТекСтрокаТовары.Номенклатура;

    // Заполняем ресурсы
    Движение.Договор = ЭтотОбъект.ДоговорКонтрагента;
    Движение.Сумма = ТекСтрокаТовары.Сумма;

КонецЦикла;

Платформа 1С автоматически позаботится об остальном. При проведении документа эти движения будут записаны в базу данных. При отмене проведения — автоматически удалены. Никакого дополнительного кода не требуется!

Шаг 3. Отображение данных в форме клиента

Данные хранятся в регистре, но пользователю нужно видеть их в карточке клиента. Для этого мы настроим форму элемента справочника "Клиенты".

  1. Откроем основную форму элемента справочника "Клиенты" в конфигураторе.
  2. Добавим на форму новый элемент — Таблица.
  3. В свойствах этой таблицы в качестве данных укажем новый реквизит формы, который мы создадим с типом ДинамическийСписок.
  4. В свойствах созданного динамического списка найдем свойство ОсновнаяТаблица и выберем наш регистр сведений "ПриобретенныеАвтомобили".
  5. Чтобы в таблице отображались автомобили только текущего клиента, настроим отбор. Самый простой способ — через свойство Связи параметров выбора. Установим связь: `Объект.Ссылка` -> `Клиент`. Система поймет, что нужно установить отбор по полю `Клиент` регистра, равное ссылке на открытый элемент справочника.

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

Выводы

Мы рассмотрели два способа решения задачи. Хотя первый, прямой метод, кажется проще на первый взгляд, он несет в себе архитектурные проблемы и требует дополнительной работы для корректной обработки отмены проведения.

Второй подход с использованием регистра сведений является стандартом в разработке 1С, потому что он:

Для серьезной работы, и тем более для дипломного проекта, настоятельно рекомендуется использовать именно второй подход.

← На главную