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