Рассмотрим распространенную задачу для начинающих разработчиков 1С: необходимо, чтобы при проведении документа "Реализация товара" информация о купленных товарах (в нашем примере — автомобилях) автоматически добавлялась в карточку клиента, который совершил покупку. То есть, мы выбираем клиента в документе, заполняем табличную часть товарами, проводим документ, и после этого в справочнике "Клиенты", открыв карточку этого покупателя, мы должны увидеть список приобретенных им автомобилей.
Проанализируем два подхода к решению этой задачи. Первый — быстрый и прямой, который заключается в непосредственном изменении данных справочника. Второй — более профессиональный и надежный, с использованием регистра сведений. Для учебного проекта или диплома второй подход является предпочтительным, так как демонстрирует более глубокое понимание архитектуры 1С.
Этот способ заключается в том, чтобы в момент проведения документа получить программный доступ к объекту нужного клиента и добавить в его табличную часть новые строки.
Основная логика и частые ошибки
Главная ошибка, которую часто допускают новички, — это попытка создать нового клиента вместо изменения существующего. Код вроде СпрКлиенты = Справочники.Клиенты.СоздатьЭлемент() всегда будет создавать пустой элемент справочника, а не работать с тем, который выбран в документе.
Правильный алгоритм действий таков:
ОбработкаПроведения(). Это гарантирует, что изменения будут внесены только после успешного проведения документа.ПолучитьОбъект().Добавить().Записать().Пример кода
Посмотрим на пример реализации. Предположим, в документе "РеализацияТовара" есть реквизит шапки Клиент (тип `СправочникСсылка.Клиенты`) и табличная часть Товары с колонкой Номенклатура. В справочнике "Клиенты" есть табличная часть Автомобили с колонкой НаименованиеАвто.
// Код размещается в модуле объекта документа "РеализацияТовара"
// в процедуре ОбработкаПроведения()
// Получаем ссылку на клиента из реквизита документа
СсылкаНаКлиента = ЭтотОбъект.Клиент;
// Обязательно проверяем, что клиент в документе указан
Если НЕ СсылкаНаКлиента.Пустая() Тогда
// Получаем ОБЪЕКТ справочника для его последующего изменения
КлиентОбъект = СсылкаНаКлиента.ПолучитьОбъект();
// Перебираем все строки из табличной части "Товары" нашего документа
Для Каждого ТекСтрокаТовары Из ЭтотОбъект.Товары Цикл
// Добавляем новую пустую строку в табличную часть "Автомобили" у клиента
НоваяСтрокаАвто = КлиентОбъект.Автомобили.Добавить();
// Заполняем реквизиты новой строки данными из документа
НоваяСтрокаАвто.НаименованиеАвто = ТекСтрокаТовары.Номенклатура;
// Можно добавить и другие данные, например, договор или дату покупки
// НоваяСтрокаАвто.Договор = ЭтотОбъект.ДоговорКонтрагента;
// НоваяСтрокаАвто.ДатаПокупки = ЭтотОбъект.Дата;
КонецЦикла;
// После добавления всех строк записываем измененный объект клиента в базу данных.
// Важно делать это один раз после цикла, а не внутри него.
КлиентОбъект.Записать();
КонецЕсли;
Недостатки прямого подхода
Несмотря на то, что этот метод работает, он считается неоптимальным и несет в себе риски:
Это более правильный и масштабируемый метод, который соответствует лучшим практикам разработки на платформе 1С. Суть в том, чтобы не хранить историю продаж внутри справочника, а вынести ее в отдельный объект — регистр сведений. Карточка клиента при этом не хранит данные, а лишь динамически их отображает из этого регистра.
Разберем реализацию по шагам.
Шаг 1. Создание регистра сведений
В конфигураторе создадим новый объект — Регистр сведений. Назовем его, например, "ПриобретенныеАвтомобили".
Клиент (тип: СправочникСсылка.Клиенты)Автомобиль (тип: СправочникСсылка.Номенклатура)Договор (тип: СправочникСсылка.ДоговорыКонтрагентов)Сумма (тип: Число)Важно: в сам справочник "Клиенты" мы не добавляем табличную часть "Автомобили". Он остается "чистым".
Шаг 2. Запись данных в регистр при проведении документа
Теперь изменим код в процедуре ОбработкаПроведения() нашего документа. Вместо работы с объектом клиента мы будем создавать "движения" — так называются записи в регистрах, подчиненных регистратору.
// Код размещается в модуле объекта документа "РеализацияТовара"
// в процедуре ОбработкаПроведения()
// Устанавливаем флаг, что этот документ будет записывать движения в наш регистр
Движения.ПриобретенныеАвтомобили.Записывать = Истина;
// Перебираем строки табличной части "Товары"
Для Каждого ТекСтрокаТовары Из ЭтотОбъект.Товары Цикл
// Создаем новое движение (запись) в регистре
Движение = Движения.ПриобретенныеАвтомобили.Добавить();
// Заполняем измерения
Движение.Период = Дата; // Период записи
Движение.Клиент = ЭтотОбъект.Клиент;
Движение.Автомобиль = ТекСтрокаТовары.Номенклатура;
// Заполняем ресурсы
Движение.Договор = ЭтотОбъект.ДоговорКонтрагента;
Движение.Сумма = ТекСтрокаТовары.Сумма;
КонецЦикла;
Платформа 1С автоматически позаботится об остальном. При проведении документа эти движения будут записаны в базу данных. При отмене проведения — автоматически удалены. Никакого дополнительного кода не требуется!
Шаг 3. Отображение данных в форме клиента
Данные хранятся в регистре, но пользователю нужно видеть их в карточке клиента. Для этого мы настроим форму элемента справочника "Клиенты".
ДинамическийСписок.Теперь при открытии карточки любого клиента, система автоматически сделает запрос к регистру сведений, отберет все записи, связанные с этим клиентом, и покажет их в нашей таблице.
Мы рассмотрели два способа решения задачи. Хотя первый, прямой метод, кажется проще на первый взгляд, он несет в себе архитектурные проблемы и требует дополнительной работы для корректной обработки отмены проведения.
Второй подход с использованием регистра сведений является стандартом в разработке 1С, потому что он:
Для серьезной работы, и тем более для дипломного проекта, настоятельно рекомендуется использовать именно второй подход.